from __future__ import annotations

import os
from collections.abc import Callable
from pathlib import Path
from typing import Annotated, Any, Final

from fastapi import APIRouter, HTTPException, Query
from fastapi import Path as PathParameter

from k1link.simulation import (
    QualificationRun,
    QualificationRunIntegrityError,
    QualificationRunNotFoundError,
    QualificationRunStore,
)

POLYGON_RUNS_ROOT_ENV: Final = "MISSIONCORE_POLYGON_RUNS_ROOT"
CATALOG_SCHEMA: Final = "missioncore.polygon-run-catalog/v1"
DETAIL_SCHEMA: Final = "missioncore.polygon-run-detail/v1"
READ_ONLY_LIMITATIONS: Final[tuple[str, ...]] = (
    "UI-0 публикует только квалификационные доказательства; "
    "lifecycle-операции и команды отсутствуют.",
    "Артефакты представлены относительными метаданными; их содержимое не публикуется этим API.",
    "Терминальное состояние прогона не означает приёмку навигации, "
    "восприятия или физической безопасности.",
)

RootProvider = Callable[[], Path | None]


def configured_polygon_runs_root() -> Path | None:
    raw = os.environ.get(POLYGON_RUNS_ROOT_ENV)
    if raw is None or not raw.strip():
        return None
    return Path(raw.strip()).expanduser()


def build_polygon_router(
    *,
    root_provider: RootProvider = configured_polygon_runs_root,
) -> APIRouter:
    router = APIRouter(prefix="/api/v1/polygon", tags=["polygon"])

    @router.get("/runs")
    def list_polygon_runs(
        limit: Annotated[int, Query(ge=1, le=100)] = 20,
    ) -> dict[str, Any]:
        store = _open_read_only_store(root_provider)
        try:
            ordered = sorted(
                store.list_runs(),
                key=lambda run: (run.created_at_utc, run.run_id),
                reverse=True,
            )
        except QualificationRunIntegrityError as exc:
            raise HTTPException(
                status_code=500,
                detail="Журнал прогонов Полигона не прошёл проверку целостности.",
            ) from exc
        return {
            "schema_version": CATALOG_SCHEMA,
            "access": "read-only",
            "items": [_run_summary(run) for run in ordered[:limit]],
            "total": len(ordered),
            "limitations": list(READ_ONLY_LIMITATIONS),
        }

    @router.get("/runs/{run_id}")
    def get_polygon_run(
        run_id: Annotated[
            str,
            PathParameter(pattern=r"^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$"),
        ],
        event_limit: Annotated[int, Query(ge=1, le=500)] = 200,
    ) -> dict[str, Any]:
        store = _open_read_only_store(root_provider)
        try:
            run = store.load(run_id)
            events = store.list_events(run_id)
            commands = store.list_commands(run_id)
        except QualificationRunNotFoundError as exc:
            raise HTTPException(status_code=404, detail="Прогон Полигона не найден.") from exc
        except QualificationRunIntegrityError as exc:
            raise HTTPException(
                status_code=500,
                detail="Доказательства прогона не прошли проверку целостности.",
            ) from exc
        visible_events = events[-event_limit:]
        return {
            "schema_version": DETAIL_SCHEMA,
            "access": "read-only",
            "run": {
                **_run_summary(run),
                "scenario_sha256": run.scenario_sha256,
                "profile_sha256": run.profile_sha256,
                "host_profile_sha256": run.host_profile_sha256,
                "seed": run.seed,
                "parent_run_id": run.parent_run_id,
                "providers": [provider.to_dict() for provider in run.providers],
                "authority": run.authority.to_dict(),
            },
            "events": [event.to_dict() for event in visible_events],
            "events_total": len(events),
            "events_truncated": len(visible_events) != len(events),
            "commands": {
                "count": len(commands),
                "content_exposed": False,
            },
            "artifacts": [artifact.to_dict() for artifact in run.artifacts],
            "limitations": list(READ_ONLY_LIMITATIONS),
        }

    return router


def _open_read_only_store(root_provider: RootProvider) -> QualificationRunStore:
    root = root_provider()
    if root is None:
        raise HTTPException(
            status_code=503,
            detail="Источник журналов Полигона не настроен на этом экземпляре Mission Core.",
        )
    if not root.is_absolute():
        raise HTTPException(
            status_code=503,
            detail="Источник журналов Полигона настроен некорректно.",
        )
    try:
        return QualificationRunStore(root, read_only=True)
    except QualificationRunIntegrityError as exc:
        raise HTTPException(
            status_code=503,
            detail="Источник журналов Полигона недоступен или настроен некорректно.",
        ) from exc


def _run_summary(run: QualificationRun) -> dict[str, Any]:
    return {
        "run_id": run.run_id,
        "episode_id": run.episode_id,
        "kind": run.kind.value,
        "state": run.state.value,
        "created_at_utc": run.created_at_utc,
        "started_at_utc": run.started_at_utc,
        "ended_at_utc": run.ended_at_utc,
        "terminal_reason": run.terminal_reason,
        "scenario_generation": run.scenario_generation,
        "profile_generation": run.profile_generation,
        "mission_core_commit": run.mission_core_commit,
        "host_profile_id": run.host_profile_id,
        "reproducibility_tier": run.reproducibility_tier.value,
        "clock_domain": run.clock_domain,
        "revision": run.revision,
        "provider_ids": [provider.identifier for provider in run.providers],
        "artifact_count": len(run.artifacts),
    }
