import os
import shutil
from configparser import SafeConfigParser
from invoke import task


@task
def create_model(_, project):
    """ creates a sqlalchemy model package inside project """
    model_path = os.path.abspath(os.path.join(project, "model"))
    if not os.path.isdir(model_path):
        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:
    @declared_attr
    def __tablename__(cls):
        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
    ctx.run(f"alembic init database/{name}")
    parser = SafeConfigParser()
    with open("alembic.ini", "r") as configfile:
        parser.readfp(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):
    path = os.getenv("PYTHONPATH", "")
    env = {"PYTHONPATH": ".:" + path}
    return ctx.run(cmd, env=env)


@task
def 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 """
    _run_with_pythonpath(ctx, f"alembic upgrade {revision}")


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