from __future__ import annotations

from typing import Any, Callable

from niannian.llm.router import LLMRouter
from niannian.llm.types import LLMUnavailable
from niannian.personas import BRAINSTEM, MODULE_PERSONAS


class ApiRouter:
    """三层 API 路由：primary → module_fallback → global_fallback。"""

    def __init__(
        self,
        config: dict[str, Any],
        providers_config: dict[str, Any] | None = None,
        *,
        show_trace: bool = True,
    ) -> None:
        self._cfg = config.get("api", {})
        self._show_trace = show_trace
        self._llm = LLMRouter(config, providers_config, show_trace=show_trace)

    @property
    def llm(self) -> LLMRouter:
        return self._llm

    def reload_llm(self, config: dict[str, Any], providers_config: dict[str, Any]) -> None:
        self._cfg = config.get("api", {})
        self._llm.reload_llm(config, providers_config)

    def is_llm_configured(self, module: str) -> bool:
        return self._llm.is_module_configured(module)

    def call(
        self,
        module: str,
        fn: Callable[[], Any],
        *,
        fallback_fn: Callable[[], Any] | None = None,
    ) -> Any:
        try:
            return fn()
        except LLMUnavailable:
            if fallback_fn:
                return fallback_fn()
            raise
        except Exception:
            if fallback_fn:
                return fallback_fn()
            raise

    @staticmethod
    def trace_line(msg: str) -> str:
        return f"[{BRAINSTEM}] {msg}"

    @staticmethod
    def persona(module: str) -> str:
        return MODULE_PERSONAS.get(module, BRAINSTEM)
