"""Report whether the database schema matches the code (STATE-WP-0083-T07).

Central ran two revisions behind the code it was serving, and `review_contracts`
did not exist there although its migration shipped inside the running image.
Nothing surfaced that: the API starts happily against a schema it was not built
for, and only fails when a request happens to touch the missing table.

A hub that cannot say which schema it is running has the same problem as a
projection that cannot name its source commit — it is asserting correctness it
cannot demonstrate.
"""

from __future__ import annotations

from functools import lru_cache
from pathlib import Path
from typing import Any

from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession

_MIGRATIONS = Path(__file__).resolve().parents[2] / "migrations"


@lru_cache(maxsize=1)
def code_head_revision() -> str | None:
    """The head revision the shipped migration scripts define.

    Read from the migration files rather than the database: this is what the
    code expects, and it must be knowable without a working connection.
    """
    try:
        from alembic.config import Config
        from alembic.script import ScriptDirectory

        cfg = Config()
        cfg.set_main_option("script_location", str(_MIGRATIONS))
        heads = ScriptDirectory.from_config(cfg).get_heads()
        return heads[0] if len(heads) == 1 else ",".join(sorted(heads)) or None
    except Exception:
        return None


async def db_revision(session: AsyncSession) -> str | None:
    try:
        result = await session.execute(text("select version_num from alembic_version"))
        return result.scalar()
    except Exception:
        return None


async def schema_state(session: AsyncSession) -> dict[str, Any]:
    applied = await db_revision(session)
    expected = code_head_revision()
    # "unknown" is deliberately not "ok": an instance that cannot determine its
    # own schema state must not report agreement it has not established.
    if applied is None or expected is None:
        status = "unknown"
    elif applied == expected:
        status = "ok"
    else:
        status = "behind"
    return {"status": status, "applied": applied, "expected": expected}
