"""
governance_service.py
---------------------
Governance and safety orchestration layer for HIEROMEM.

Manages the Governance Safety Region (GSR) — the mathematical stability
domain that constrains dynamic parameters (λ, τ, θ, Nmax, b) ensuring
global trust convergence, bounded memory growth, and continuity of learning.

This service enables:
  • Safe runtime parameter inspection and updates
  • Validation of new parameter sets within GSR bounds
  • Risk assessment and safety flagging for adaptive governance

Author: Sai Rishi Kiran Mannava
"""

from __future__ import annotations

from typing import Any, Callable, Dict, TypeVar

from hieromem_core.governance import GovernanceSafetyRegion
from hieromem_api.instrumentation.prometheus import (
    update_episode_metrics,
    update_stability_metrics,
)
from hieromem_api.instrumentation.tracing import trace_function
from hieromem_api.models.responses import GSRViewResponse, ParamUpdateResponse

_T = TypeVar("_T")


class GovernanceService:
    """Administrative interface for the Governance Safety Region."""

    def __init__(self, gsr: GovernanceSafetyRegion,
                 tracer: Any | None = None) -> None:
        self.gsr = gsr
        self.tracer = tracer

    # ------------------------------------------------------------------ #
    # Internal helpers
    # ------------------------------------------------------------------ #

    def _run(self, name: str, func: Callable[[], _T]) -> _T:
        traced = trace_function(self.tracer, name=name)(func)
        return traced()

    def _serialise_view(
        self, description: Dict[str, Any]
    ) -> tuple[dict[str, float], bool, str, dict[str, list[float]]]:
        bounds_raw = description.get("bounds", {})
        bounds: dict[str, list[float]] = {}
        for key, value in bounds_raw.items():
            if isinstance(value, tuple):
                bounds[key] = [float(part) for part in value]
            elif isinstance(value, list):
                bounds[key] = [float(part) for part in value]
            else:
                bounds[key] = [float(value)]

        region = {
            "lambda": float(description["lam"]),
            "tau": float(description["tau"]),
            "theta": float(description["theta"]),
            "Nmax": float(description["Nmax"]),
            "b": float(description["b"]),
        }

        valid = bool(description.get("valid", self.gsr.is_valid()))
        risk = str(description.get("risk_level", self.gsr.risk_level()))

        return region, valid, risk, bounds

    # ------------------------------------------------------------------ #
    # GSR Introspection
    # ------------------------------------------------------------------ #

    def snapshot(self) -> GSRViewResponse:
        """Return the current Governance Safety Region state."""

        def _impl() -> GSRViewResponse:
            description = self.gsr.describe()
            region, valid, risk, bounds = self._serialise_view(description)
            return GSRViewResponse(
                region=region,
                is_valid=valid,
                risk_level=risk,
                bounds=bounds,
            )

        return self._run("gsr_snapshot", _impl)

    # ------------------------------------------------------------------ #
    # Parameter Update
    # ------------------------------------------------------------------ #

    def update(self, updates: Dict[str, Any]) -> ParamUpdateResponse:
        """Safely update one or more governance parameters."""

        def _impl() -> ParamUpdateResponse:
            allowed_keys = {"lam", "tau", "theta", "Nmax", "b"}
            filtered_updates = {k: v for k,
                                v in updates.items() if k in allowed_keys}
            if not filtered_updates:
                raise ValueError(
                    "No recognised governance parameters supplied.")

            self.gsr.update_params(**filtered_updates)
            description = self.gsr.describe()
            _, valid, _, _ = self._serialise_view(description)

            changed = {key: description[key] for key in filtered_updates}

            message = (
                "Parameters updated successfully within GSR."
                if valid
                else "Warning: parameters updated, but GSR stability risk detected."
            )

            # Optional: update metrics to reflect new operational constraints
            update_episode_metrics(
                total=0,
                avg_trust=0.0,
                namespace="global",
                capacity=description.get("Nmax"),
            )
            update_stability_metrics(
                namespace="global",
                distortion_bound=0.0,
                contraction_factor=1.0,
                lyapunov_margin=0.0,
                lyapunov_warning=False,
            )

            return ParamUpdateResponse(
                status="ok",
                message=message,
                updated=changed,
                gsr_valid=valid,
                gsr=description,
            )

        return self._run("gsr_update", _impl)

    # ------------------------------------------------------------------ #
    # Risk Assessment
    # ------------------------------------------------------------------ #

    def risk_report(self) -> Dict[str, Any]:
        """Return a detailed risk assessment of the current GSR configuration."""

        def _impl() -> Dict[str, Any]:
            description = self.gsr.describe()
            region, valid, risk, bounds = self._serialise_view(description)

            return {
                "parameters": region,
                "stability": "stable" if valid else "unstable",
                "risk_level": risk,
                "bounds": bounds,
            }

        return self._run("gsr_risk_assessment", _impl)
