from __future__ import annotations

import asyncio
import subprocess
import sys
from pathlib import Path

from core.config.initial.init_data import initialize_data
from core.logging import get_logger

logger = get_logger("core.runtime.cli")


def _resolve_alembic_path() -> Path:
    """Resolve alembic.ini path relative to project root."""
    project_root = Path(__file__).parents[3]
    alembic_path = project_root / "alembic" / "alembic.ini"
    if not alembic_path.exists():
        raise FileNotFoundError(f"Alembic config not found at {alembic_path}")
    return alembic_path


def _redact_sensitive(text: str) -> str:
    """Redact sensitive information from log output."""
    import re

    SENSITIVE_KEYS = ("password", "token", "secret", "api_key")
    pattern = r"(?i)(" + "|".join(SENSITIVE_KEYS) + r")\s*[:=]\s*[\"']?([^\"',\n]+)"
    redacted = re.sub(pattern, r"\1=***", text)

    auth_pattern = r"(?i)(authorization)\s*[:=]\s*[^\n]+"
    redacted = re.sub(auth_pattern, r"\1=***", redacted)

    redacted = re.sub(r"://[^:]+:[^@]+@", "://***:***@", redacted)
    return redacted


def run_migrations() -> bool:
    """Run alembic migrations in a subprocess to avoid event loop conflicts."""
    import os

    logger.info("Running alembic migrations")
    try:
        config_path = _resolve_alembic_path()
        logger.info("Using alembic config", path=str(config_path))

        env = os.environ.copy()
        env["PYTHONPATH"] = "backend/src"

        result = subprocess.run(
            ["uv", "run", "alembic", "-c", str(config_path), "upgrade", "head"],
            cwd=Path(__file__).parents[3],
            env=env,
            capture_output=True,
            text=True,
        )

        if result.returncode != 0:
            logger.error(
                "Migration failed",
                returncode=result.returncode,
                stderr=_redact_sensitive(result.stderr),
            )
            return False

        logger.info("Migrations completed successfully")
        return True
    except Exception as e:
        logger.error("Migration failed", error=str(e))
        return False


async def run_init_data() -> bool:
    """Initialize bootstrap data."""
    logger.info("Running init-data")
    try:
        result = await initialize_data()
        if result:
            logger.info("Init-data completed successfully")
        else:
            logger.error("Init-data returned False")
        return result
    except Exception as e:
        logger.error("Init-data failed", error=str(e))
        return False


async def bootstrap() -> bool:
    """Run migrations followed by init-data."""
    logger.info("Starting bootstrap (migrate + init-data)")

    if not run_migrations():
        logger.error("Bootstrap aborted: migrations failed")
        return False

    if not await run_init_data():
        logger.error("Bootstrap aborted: init-data failed")
        return False

    logger.info("Bootstrap completed successfully")
    return True


def main() -> int:
    """CLI entry point."""
    if len(sys.argv) < 2:
        logger.error("No command provided")
        logger.info("Usage: python -m core.runtime.cli <command>")
        logger.info("Available commands: migrate, init-data, bootstrap")
        return 1

    command = sys.argv[1]

    if command == "migrate":
        success = run_migrations()
    elif command == "init-data":
        success = asyncio.run(run_init_data())
    elif command == "bootstrap":
        success = asyncio.run(bootstrap())
    else:
        logger.error("Unknown command", command=command)
        logger.info("Available commands: migrate, init-data, bootstrap")
        return 1

    return 0 if success else 1


if __name__ == "__main__":
    sys.exit(main())
