"""Docker entrypoint: wait for DB, reconcile Alembic state, migrate, start API."""

from __future__ import annotations

import subprocess
import sys
import time
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

from alembic import command
from alembic.config import Config
from sqlalchemy import create_engine, inspect, text

from app.core.install_secrets import ensure_install_secrets
from app.core.config import settings

INITIAL_REVISION = "20260711_0001"
HEAD_REVISION = "20260714_0005"
SCHEMA_TABLES = (
    "content_pages",
    "email_verification_tokens",
    "password_reset_tokens",
    "refresh_tokens",
    "user_profiles",
    "users",
)


def wait_for_database(max_attempts: int = 30, delay_seconds: float = 1.0):
    engine = create_engine(settings.database_url)
    last_error: Exception | None = None
    for _ in range(max_attempts):
        try:
            with engine.connect() as connection:
                connection.execute(text("SELECT 1"))
            return engine
        except Exception as exc:
            last_error = exc
            time.sleep(delay_seconds)
    detail = str(last_error or "unknown error")
    hint = ""
    if "password authentication failed" in detail or "does not exist" in detail:
        hint = (
            "\n\nPostgres credentials in install.env do not match the existing database volume "
            "(common if docker compose ran before bootstrap_install.py).\n"
            "Local dev fix — deletes Docker DB data:\n"
            "  docker compose --profile docker-web down -v\n"
            "  docker compose --profile docker-web up -d --build\n"
            "See docs/deploy.md#восстановление-секретов"
        )
    raise RuntimeError(f"Database is unavailable: {detail}{hint}") from last_error


def current_revision(engine) -> str | None:
    inspector = inspect(engine)
    if "alembic_version" not in inspector.get_table_names():
        return None
    with engine.connect() as connection:
        return connection.execute(text("SELECT version_num FROM alembic_version")).scalar()


def _reset_schema(engine) -> None:
    cascade = " CASCADE" if engine.dialect.name == "postgresql" else ""
    with engine.begin() as connection:
        for table in SCHEMA_TABLES:
            connection.execute(text(f'DROP TABLE IF EXISTS "{table}"{cascade}'))
        connection.execute(text(f'DROP TABLE IF EXISTS "alembic_version"{cascade}'))


def run_migrations(engine) -> None:
    config = Config("alembic.ini")
    tables = set(inspect(engine).get_table_names())
    revision = current_revision(engine)
    schema_tables = set(SCHEMA_TABLES)
    existing_schema = tables & schema_tables

    if existing_schema:
        if schema_tables.issubset(tables):
            if revision is None:
                command.stamp(config, INITIAL_REVISION)
        else:
            _reset_schema(engine)

    command.upgrade(config, "head")


def main() -> None:
    ensure_install_secrets()
    engine = wait_for_database()
    run_migrations(engine)
    subprocess.run(
        [sys.executable, "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"],
        check=True,
    )


if __name__ == "__main__":
    main()
