from __future__ import annotations

import argparse
import json
from pathlib import Path

from govoplan_core.db.bootstrap import bootstrap_dev_data
from govoplan_core.db.migrations import (
    ModuleMigrationTaskExecutionError,
    POST_MIGRATION_TASK_PHASES,
    PRE_MIGRATION_TASK_PHASES,
    migrate_database,
    run_registered_module_migration_tasks,
)
from govoplan_core.db.migration_lock import deployment_migration_lock
from govoplan_core.db.session import configure_database, get_database
from govoplan_core.settings import settings


def main() -> None:
    parser = argparse.ArgumentParser(description="Initialize the GovOPlaN database")
    parser.add_argument("--database-url", default=settings.database_url, help="Database URL to migrate")
    parser.add_argument(
        "--migration-track",
        default=settings.migration_track,
        choices=("release", "dev"),
        help="Alembic migration track to load: release uses squashed release shortcuts; dev uses detailed development chains.",
    )
    parser.add_argument("--enabled-module", action="append", default=[], help="Target enabled module id used to discover module migrations; may be repeated.")
    parser.add_argument("--migration-module", action="append", default=[], help="Module id whose migration heads should be upgraded in this order before final heads.")
    parser.add_argument("--migration-task-record-output", type=Path, help="Write executed module migration task records to this JSON file.")
    parser.add_argument(
        "--migration-lock-timeout-seconds",
        type=float,
        default=900.0,
        help="Maximum wait for the deployment-wide PostgreSQL advisory lock.",
    )
    parser.add_argument("--with-dev-data", action="store_true", help="Create default tenant/user/roles and a development API key")
    parser.add_argument("--dev-api-key", default=settings.dev_bootstrap_api_key, help="Development API key secret to create")
    args = parser.parse_args()

    configure_database(args.database_url)
    enabled_modules = tuple(args.enabled_module) if args.enabled_module else None
    migration_order = tuple(args.migration_module) if args.migration_module else None
    task_records: list[dict[str, object]] = []
    try:
        with deployment_migration_lock(
            args.database_url,
            installation_id=settings.installation_id,
            migration_track=args.migration_track,
            timeout_seconds=args.migration_lock_timeout_seconds,
        ):
            _run_migration_tasks(
                task_records,
                database_url=args.database_url,
                enabled_modules=enabled_modules,
                migration_order=migration_order,
                phases=PRE_MIGRATION_TASK_PHASES,
            )
            migration = migrate_database(
                database_url=args.database_url,
                enabled_modules=enabled_modules,
                migration_module_order=migration_order,
                migration_track=args.migration_track,
            )
            _run_migration_tasks(
                task_records,
                database_url=args.database_url,
                enabled_modules=enabled_modules,
                migration_order=migration_order,
                phases=POST_MIGRATION_TASK_PHASES,
            )
    finally:
        if args.migration_task_record_output:
            args.migration_task_record_output.parent.mkdir(parents=True, exist_ok=True)
            args.migration_task_record_output.write_text(json.dumps(task_records, indent=2, sort_keys=True) + "\n", encoding="utf-8")
    if task_records:
        print(f"Executed {len(task_records)} module migration task(s).")
    if migration.reconciled_revision:
        print(f"Reconciled legacy database marker to {migration.reconciled_revision}.")
    print(f"Database schema upgraded to {migration.current_revision}.")

    if args.with_dev_data:
        with get_database().SessionLocal() as session:
            result = bootstrap_dev_data(session, api_key_secret=args.dev_api_key)
            print(f"Tenant: {result.tenant.slug} ({result.tenant.id})")
            print(f"User: {result.user.email} ({result.user.id})")
            if result.created_api_key:
                print("Development API key created:")
                print(result.created_api_key.secret)
            else:
                print("Development API key already exists or was not requested.")


def _run_migration_tasks(
    target: list[dict[str, object]],
    *,
    database_url: str,
    enabled_modules: tuple[str, ...] | None,
    migration_order: tuple[str, ...] | None,
    phases: tuple[str, ...],
) -> None:
    try:
        records = run_registered_module_migration_tasks(
            database_url=database_url,
            enabled_modules=enabled_modules,
            migration_module_order=migration_order,
            phases=phases,
        )
    except ModuleMigrationTaskExecutionError as exc:
        target.extend(exc.records)
        raise
    target.extend(records)


if __name__ == "__main__":
    main()
