from .session import Session
from .version import version
import os
import datetime

dev = False
version_str = f"SQL-Cable Build {version}{'-dev' if dev else ''}"


def get_lastest_migration_file(new=False):
    # gets all files with migration_ in the name
    all_files = [f for f in os.listdir('migrations') if os.path.isfile(os.path.join('migrations', f)) and 'migration_' in f and f != '__init__.py']
    if len(all_files) > 0:
        # sorts the list by number to find the lastest one and make that into a migration file name
        if new:
            file_name = "migration_" + str(int(sorted(all_files, reverse=True)[0].replace('migration_', '').replace('.py', '')) + 1) + ".py"
        else:
            file_name = "migration_" + str(int(sorted(all_files, reverse=True)[0].replace('migration_', '').replace('.py', ''))) + ".py"
    else:
        file_name = "migration_" + '1' + ".py"
    return file_name


class DB:
    def __init__(self, app=None):
        self.models = []
        if app:
            self.init(app)

    def init(self, app):
        self.db_path = app.config['DB_PATH']
        # start the db instances session
        # NOTE there only should ever be one made
        self.session = Session(self.db_path)
        if dev:
            print(f"""WARNING you are running a dev build of SQL-Cable build version: {version}-dev
This build maybe unstable and have bugs or other problems
Please update to the latest full build of SQL-Cable by
typing 'pip install sql-cable' in the cmd""")

    def register_model(self, model):
        # model = model()
        model.db_path = self.db_path
        model.session = self.session
        model.__init__(model)
        model.load_queries(model)
        model.check_for_changes(model)
        self.models.append(model)

    def make_migrations(self, path=None, test=False):
        # if migrations folder does not exist make one and a __init__.py file
        if not os.path.isdir('migrations'):
            os.mkdir('migrations')
            with open(path if path else os.path.join('migrations', '__init__.py'), 'w') as f:
                pass
        # getting the new migration files file name
        file_name = get_lastest_migration_file(new=True)
        file_str = f"# Generated by {version_str} on {str(datetime.datetime.now())[:-7]}\nfrom sql_cable.migrations import Migration"
        # getting all the migrations from models and adding them to the file str
        model_names = []
        for model in self.models:
            changes = model.check_for_changes(model)
            if changes != []:
                migrations_str = model.generate_migrations(model, changes)
                file_str += migrations_str
                model_names.append(f'{model.model_name}()')
        if not model_names:
            print("No migrations to be made")
            return None
        # making the model_names list into a list of instances of the migrations class's
        # eg changing models = models = ['test1()'] to models = [test1()]
        file_str += "\n\n\nmodels = " + str(model_names).replace("'", '')

        # making the migration file and adding it to the __init__.py file
        file_path = os.path.join("migrations", file_name)
        with open(path if path else file_path, 'w') as f:
            f.write(file_str)
        with open(path if path else os.path.join("migrations", "__init__.py"), 'a') as f:
            f.write(f"\nfrom . import {file_name[:-3]}")
        if test:
            return file_path

    def migrate(self):
        if not os.path.isdir('migrations'):
            print("No dir named migrations could be found.")
            return None
        # gettings the latest migration file and imports the migrations package
        migrate_file_name = get_lastest_migration_file()
        migrate_file = __import__("migrations")
        # gets all the models that have changes
        _locals = locals()
        exec(f"models = migrate_file.{migrate_file_name[:-3]}.models", _locals)
        for model in _locals['models']:
            model.run_migrations(self.db_path, self.session)
