"""Pathway 注册表 — routes + sticky 配置。"""

from __future__ import annotations

import shutil
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

import yaml

from niannian.cognitive.planes import Regime


def _registry_path(config: dict[str, Any], home: Path | None = None) -> Path:
    cognitive = config.get("cognitive") or {}
    raw = cognitive.get("pathway_registry") or "config/cognitive/pathway_registry.yaml"
    path = Path(raw)
    if path.is_file():
        return path
    if home is not None:
        candidate = home / raw
        if candidate.is_file():
            return candidate
    return path


class PathwayRegistry:
    def __init__(self, config: dict[str, Any], *, home: Path | None = None) -> None:
        self._config = config
        self._home = home
        self._path = _registry_path(config, home)

    @property
    def path(self) -> Path:
        return self._path

    def exists(self) -> bool:
        return self._path.is_file()

    def load(self) -> dict[str, Any]:
        if not self._path.is_file():
            return {"routes": [], "sticky": {}}
        with self._path.open(encoding="utf-8") as f:
            data = yaml.safe_load(f) or {}
        return data if isinstance(data, dict) else {"routes": [], "sticky": {}}

    def save(self, data: dict[str, Any]) -> None:
        self._path.parent.mkdir(parents=True, exist_ok=True)
        backup_dir = self._path.parent.parent / "self" / "history"
        if self._path.is_file():
            backup_dir.mkdir(parents=True, exist_ok=True)
            stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
            shutil.copy2(self._path, backup_dir / f"pathway_registry.{stamp}.yaml")
        self._path.write_text(yaml.safe_dump(data, allow_unicode=True, sort_keys=False), encoding="utf-8")

    def list_routes(self) -> list[dict[str, Any]]:
        data = self.load()
        routes = data.get("routes")
        if not isinstance(routes, list):
            return []
        return [r for r in routes if isinstance(r, dict) and r.get("id")]

    def get_route(self, route_id: str) -> dict[str, Any] | None:
        for route in self.list_routes():
            if route.get("id") == route_id:
                return route
        return None

    def sticky_config(self) -> dict[str, Any]:
        data = self.load()
        sticky = data.get("sticky")
        if not isinstance(sticky, dict):
            return {"enabled": True, "hits_to_sticky": 3}
        return {
            "enabled": bool(sticky.get("enabled", True)),
            "hits_to_sticky": int(sticky.get("hits_to_sticky") or 3),
            "regime_hits": sticky.get("regime_hits") if isinstance(sticky.get("regime_hits"), dict) else {},
        }

    def preview(
        self,
        *,
        text: str,
        regime: Regime | None = None,
        object_id: str | None = None,
        session_meta: dict[str, Any] | None = None,
    ) -> dict[str, Any]:
        meta = dict(session_meta or {})
        if object_id is not None:
            meta["current_object_id"] = object_id
        if regime is not None:
            meta["regime_lock"] = regime
        from niannian.cognitive.pathway import PathwayResolver

        resolved = PathwayResolver(self._config).resolve(text, session_meta=meta)
        policy = resolved.policy
        return {
            "tier": resolved.tier,
            "route_id": resolved.route_id,
            "regime": policy.regime,
            "intent": policy.intent,
            "persona_preset": resolved.persona_preset,
            "active_planes": sorted(pid for pid in policy.planes.active if policy.planes.is_active(pid)),
            "skip_planes": sorted(policy.planes.skip),
            "trace_preview": (
                f"[Pathway:{resolved.tier}] route={resolved.route_id or '—'} "
                f"regime={policy.regime} persona={resolved.persona_preset or 'detach'}"
            ),
        }

    def to_api_dict(self) -> dict[str, Any]:
        return {
            "routes": self.list_routes(),
            "sticky": self.sticky_config(),
            "registry_path": str(self._path),
        }
