"""
    Scripts to make alembic simple
"""
import os
import shutil
from configparser import SafeConfigParser
from alembic.config import Config
from invoke import task
from bluemax.tasks.utils import confirm_action


def confirm_db_action(action, color="0;31"):
    """db are you sure? """
    db_url = get_db_url()
    return confirm_action(f"\033[{color}m{action}\033[0m {db_url}")


@task
def create_model(_, project):
    """ creates a sqlalchemy model package inside project """
    model_path = os.path.abspath(os.path.join(project, "model"))
    if os.path.isdir(model_path):
        print("model exists")
        return
    os.makedirs(model_path)
    open(os.path.join(model_path, "__init__.py"), "w")
    with open(os.path.join(model_path, "base.py"), "w") as file:
        file.write(
            '''""" Used by alembic """
from sqlalchemy.ext.declarative import declarative_base, declared_attr


class Base:
    """ Base for orm model classes """

    @declared_attr
    def __tablename__(cls):
        """ with this tablename is class name lower"""
        return cls.__name__.lower()


Base = declarative_base(cls=Base)
'''
        )


@task(default=True)
def create(ctx, name, project=None):
    """ Creates an alembic managed db """
    if project is None:
        project = name
    if not os.path.isdir("database"):
        os.makedirs("database")

    ctx.run(f"alembic init database/{name}")
    parser = SafeConfigParser()
    with open("alembic.ini", "r") as configfile:
        parser.read_file(configfile)
        for key, value in parser.items():
            print(key, value)
    parser.set("alembic", "sqlalchemy.url", f"sqlite:///{name}.sqlite3")
    with open("alembic.ini", "w") as configfile:
        parser.write(configfile)
    with open(os.path.join("database", name, "env.py"), "r") as file:
        contents = file.read()
        contents = contents.split("target_metadata = None\n")

    with open(os.path.join("database", name, "env.py"), "w") as file:
        file.write(contents[0])
        file.write("\n")
        file.write(f"from {project}.model.base import Base\n")
        file.write("target_metadata = Base.metadata\n")
        file.write(contents[1])

    create_model(ctx, project)


@task
def remove(_, name):
    """ removes a database of name from the database folder """
    db_path = os.path.abspath(os.path.join("database", name))
    if os.path.isdir(db_path):
        shutil.rmtree(db_path)
        print(f"removed {db_path}")
    alembic_file = "alembic.ini"
    if os.path.isfile(alembic_file):
        os.unlink(alembic_file)
        print(f"removed {alembic_file}")


def _run_with_pythonpath(ctx, cmd):
    """ extend the python path environment variable with cwd """
    path = os.getenv("PYTHONPATH", "")
    env = {"PYTHONPATH": ".:" + path}
    return ctx.run(cmd, env=env)


def get_db_url():
    """ get the db_url from alembic.ini """
    alembic_cfg = Config("alembic.ini")
    return alembic_cfg.get_main_option("sqlalchemy.url")


@task
def auto_revision(ctx, message):
    """ creates an autogenerated revision in alembic """
    _run_with_pythonpath(ctx, f'alembic revision --autogenerate -m "{message}"')


@task
def upgrade(ctx, revision="head"):
    """ upgrades with alembic to revision """
    if confirm_db_action("UPGRADE", color="0;32"):
        _run_with_pythonpath(ctx, f"alembic upgrade {revision}")
    # with engine.begin() as connection:
    #     alembic_cfg.attributes['connection'] = connection
    #     command.upgrade(alembic_cfg, "head")


@task
def downgrade(ctx, revision):
    """ downgrades to revsion with alembic - base is nothing!"""
    if confirm_db_action("DOWNGRADE"):
        _run_with_pythonpath(ctx, f"alembic downgrade {revision}")
