from __future__ import annotations

import typer, os

from typing import Optional, List

from svc_infra.db.core import (
    init_alembic as core_init_alembic,
    revision as core_revision,
    upgrade as core_upgrade,
    downgrade as core_downgrade,
    current as core_current,
    history as core_history,
    stamp as core_stamp,
    merge_heads as core_merge_heads,
    setup_and_migrate as core_setup_and_migrate,
)


def apply_database_url(database_url: Optional[str]) -> None:
    """If provided, set DATABASE_URL for the current process."""
    if database_url:
        os.environ["DATABASE_URL"] = database_url

def cmd_init(
        database_url: Optional[str] = typer.Option(
            None,
            help="Database URL; overrides env DATABASE_URL for this command. "
                 "Async vs sync is auto-detected from the URL."
        ),
        discover_packages: Optional[List[str]] = typer.Option(
            None,
            help="Packages to search for SQLAlchemy metadata; may pass multiple. "
                 "If omitted, automatic discovery is used."
        ),
        overwrite: bool = typer.Option(
            False,
            help="Overwrite existing files if present."
        ),
):
    """
    Initialize Alembic scaffold. The env.py variant (async vs. sync) is
    auto-detected from DATABASE_URL (if available at init time).
    """
    apply_database_url(database_url)
    core_init_alembic(
        discover_packages=discover_packages,
        overwrite=overwrite,
    )


def cmd_revision(
        message: str = typer.Option(..., "-m", "--message", help="Revision message."),
        database_url: Optional[str] = typer.Option(None, help="Database URL; overrides env for this command."),
        autogenerate: bool = typer.Option(False, help="Autogenerate migrations by comparing metadata."),
        head: Optional[str] = typer.Option("head", help="Set the head to base this revision on."),
        branch_label: Optional[str] = typer.Option(None, help="Branch label."),
        version_path: Optional[str] = typer.Option(None, help="Alternative versions/ path."),
        sql: bool = typer.Option(False, help="Don't generate Python; dump SQL to stdout."),
):
    """Create a new Alembic revision, either empty or autogenerated."""
    apply_database_url(database_url)
    core_revision(
        message=message,
        autogenerate=autogenerate,
        head=head,
        branch_label=branch_label,
        version_path=version_path,
        sql=sql,
    )


def cmd_upgrade(
        revision_target: str = typer.Argument("head", help="Target revision (default head)."),
        database_url: Optional[str] = typer.Option(None, help="Database URL; overrides env for this command."),
):
    """Upgrade to a later version."""
    apply_database_url(database_url)
    core_upgrade(revision_target=revision_target)


def cmd_downgrade(
        revision_target: str = typer.Argument("-1", help="Target revision (default -1)."),
        database_url: Optional[str] = typer.Option(None, help="Database URL; overrides env for this command."),
):
    """Downgrade to an earlier version."""
    apply_database_url(database_url)
    core_downgrade(revision_target=revision_target)


def cmd_current(
        database_url: Optional[str] = typer.Option(None, help="Database URL; overrides env for this command."),
        verbose: bool = typer.Option(False, help="Verbose output."),
):
    """Display the current revision for each database."""
    apply_database_url(database_url)
    core_current(verbose=verbose)


def cmd_history(
        database_url: Optional[str] = typer.Option(None, help="Database URL; overrides env for this command."),
        verbose: bool = typer.Option(False, help="Verbose output."),
):
    """List changeset scripts in chronological order."""
    apply_database_url(database_url)
    core_history(verbose=verbose)


def cmd_stamp(
        revision_target: str = typer.Argument("head"),
        database_url: Optional[str] = typer.Option(None, help="Database URL; overrides env for this command."),
):
    """Stamp the revision table with the given revision; don't run migrations."""
    apply_database_url(database_url)
    core_stamp(revision_target=revision_target)


def cmd_merge_heads(
        database_url: Optional[str] = typer.Option(None, help="Database URL; overrides env for this command."),
        message: Optional[str] = typer.Option(None, "-m", "--message", help="Merge revision message."),
):
    """Create a merge revision for multiple heads."""
    apply_database_url(database_url)
    core_merge_heads(message=message)


def cmd_setup_and_migrate(
        database_url: Optional[str] = typer.Option(
            None,
            help="Overrides env for this command. Async vs sync is auto-detected from the URL."
        ),
        overwrite_scaffold: bool = typer.Option(False, help="Overwrite alembic scaffold if present."),
        create_db_if_missing: bool = typer.Option(True, help="Create the database/schema if missing."),
        create_followup_revision: bool = typer.Option(True, help="Create an autogen follow-up revision if revisions already exist."),
        initial_message: str = typer.Option("initial schema"),
        followup_message: str = typer.Option("autogen"),
):
    """
    End-to-end: ensure DB exists, scaffold Alembic, create/upgrade revisions.
    Async vs. sync is inferred from DATABASE_URL.
    """
    apply_database_url(database_url)
    core_setup_and_migrate(
        overwrite_scaffold=overwrite_scaffold,
        create_db_if_missing=create_db_if_missing,
        create_followup_revision=create_followup_revision,
        initial_message=initial_message,
        followup_message=followup_message,
    )


def register(app: typer.Typer) -> None:
    app.command("init")(cmd_init)
    app.command("revision")(cmd_revision)
    app.command("upgrade")(cmd_upgrade)
    app.command("downgrade")(cmd_downgrade)
    app.command("current")(cmd_current)
    app.command("history")(cmd_history)
    app.command("stamp")(cmd_stamp)
    app.command("merge-heads")(cmd_merge_heads)
    app.command("setup-and-migrate")(cmd_setup_and_migrate)