from . import runserver
from django.core.management import call_command
from django.conf import settings
import time
import pathlib
import os.path
from django.db.utils import OperationalError
from django.db.migrations import exceptions as migrations_excs
import sys

TMP_MIGRATIONS_DIR = '__temp_migrations'

ADVICE_DELETE_TMP = (
    "Try deleting the folder {}. If that doesn't work, "
    "look for the error in your models.py."
).format(TMP_MIGRATIONS_DIR)

is_sqlite = settings.DATABASES['default']['ENGINE'].endswith('sqlite3')
if is_sqlite:
    ADVICE_DELETE_DB = (
        'Try deleting db.sqlite3.'
    )
else:
    ADVICE_DELETE_DB = 'Try deleting your database.'

class Command(runserver.Command):

    def handle_migrations(self):

        migrations_modules = {
            app_name: '{}.{}'.format(TMP_MIGRATIONS_DIR, app_name)
            for app_name in settings.INSTALLED_OTREE_APPS + ['otree']
        }

        settings.MIGRATION_MODULES = migrations_modules

        migrations_dir_path = os.path.join(settings.BASE_DIR, TMP_MIGRATIONS_DIR)
        pathlib.Path(TMP_MIGRATIONS_DIR).mkdir(exist_ok=True)

        init_file_path = os.path.join(migrations_dir_path, '__init__.py')
        pathlib.Path(init_file_path).touch(exist_ok=True)

        start = time.time()

        try:
            call_command('makemigrations', '--noinput', *migrations_modules.keys())
        except Exception as exc:
            # could be due to corrupted migrations files,
            # or
            ExceptionClass = type(exc)
            tb = sys.exc_info()[2]
            raise ExceptionClass(
                '{} - {}'.format(exc, ADVICE_DELETE_TMP)
            ).with_traceback(tb) from None

        try:
            call_command('migrate', '--noinput')
        except (OperationalError, migrations_excs.InconsistentMigrationHistory) as exc:
            ExceptionClass = type(exc)
            tb = sys.exc_info()[2]
            raise ExceptionClass(
                '{} - {}'.format(exc, ADVICE_DELETE_DB)
            ).with_traceback(tb) from None

        total_time = round(time.time() - start, 1)
        self.stdout.write('makemigrations & migrate ran in {}s'.format(total_time))

    def inner_run(self, *args, **options):

        self.handle_migrations()

        super().inner_run(*args, **options)
