"""GEC sub-client — frontier registry, on-demand GEC compute, and health queries."""

from __future__ import annotations

from typing import Any, Mapping

from sbn._http import HttpTransport

PREFIX = "/api/gec"


class GecClient:
    """On-demand GEC computation, frontier registry, and health queries.

    Provides SDK access to the SBN Generalized Efficiency Coefficient (GEC)
    compute engine, frontier registry lookups, and live frontier health
    aggregation.

    Example::

        client = SbnClient(base_url="https://api.smartblocks.network")
        client.authenticate_api_key("sbn_live_...")

        # List all frontiers from the registry
        frontiers = client.gec.list_frontiers()

        # Compute GEC₀ with optional CSK health dimensions
        result = client.gec.compute(
            y=85.0,
            x=100.0,
            frontier_id="core-ops",
            csk={"S": 0.9, "H": 0.85, "D": 0.7, "R": 0.8, "E": 0.75},
        )
        print(result["gec0"], result["metallic_label"])
    """

    def __init__(self, transport: HttpTransport) -> None:
        self._t = transport

    # ── Frontier Registry ──────────────────────────────────────────────

    def list_frontiers(
        self,
        *,
        if_none_match: str | None = None,
    ) -> dict[str, Any]:
        """Return the frontier registry with ETag support.

        Supports conditional GET via ``if_none_match`` — pass a previously
        received ETag to get a 304 if the registry hasn't changed.

        Returns ``{"domains": {...}}`` with all registered frontiers.
        """
        headers: dict[str, str] = {}
        if if_none_match:
            headers["If-None-Match"] = if_none_match
        resp = self._t.get(f"{PREFIX}/frontiers", headers=headers)
        if resp.status_code == 304:
            return {"not_modified": True}
        return resp.json()

    def get_frontier_bundle(self) -> dict[str, Any]:
        """Get the raw signed frontier bundle for integrity verification.

        Returns ``{"bundle": {...}, "snapchore_hash": "...", "version": "...",
        "loaded_at": "..."}``.
        """
        return self._t.get(f"{PREFIX}/frontiers/bundle").json()

    # ── Compute ────────────────────────────────────────────────────────

    def compute(
        self,
        y: float,
        x: float,
        *,
        frontier_id: str | None = None,
        c_max: float | None = None,
        var_y: float = 0.0,
        var_x: float = 0.0,
        var_cmax: float = 0.0,
        n: int | None = None,
        cov_yx: float | None = None,
        alpha: float = 0.05,
        csk: Mapping[str, float] | None = None,
    ) -> dict[str, Any]:
        """Compute GEC₀, confidence interval, CSK health, and metallic class.

        Parameters
        ----------
        y : float
            Validated output (yield).
        x : float
            Resource input.
        frontier_id : str, optional
            Frontier domain ID for ``c_max`` lookup from the registry.
        c_max : float, optional
            Explicit ``c_max`` — overrides ``frontier_id`` lookup.
        var_y, var_x, var_cmax : float
            Estimator variances for CI computation.
        n : int, optional
            Sample size (passed through for CI metadata).
        cov_yx : float, optional
            Covariance between y and x estimators.
        alpha : float
            Significance level for confidence interval (default 0.05).
        csk : dict, optional
            CSK health vector ``{"S": ..., "H": ..., "D": ..., "R": ...,
            "E": ...}`` for metallic classification.

        Returns
        -------
        dict
            ``{"gec0": ..., "ci": {...}, "csk": {...}, "lambda_score": ...,
            "metallic_label": "...", "attractor": {...}, "frontier": {...}}``.
        """
        body: dict[str, Any] = {"y": y, "x": x}
        if frontier_id is not None:
            body["frontier_id"] = frontier_id
        if c_max is not None:
            body["c_max"] = c_max
        if var_y != 0.0:
            body["var_y"] = var_y
        if var_x != 0.0:
            body["var_x"] = var_x
        if var_cmax != 0.0:
            body["var_cmax"] = var_cmax
        if n is not None:
            body["n"] = n
        if cov_yx is not None:
            body["cov_yx"] = cov_yx
        if alpha != 0.05:
            body["alpha"] = alpha
        if csk is not None:
            body["csk"] = dict(csk)
        return self._t.post(f"{PREFIX}/compute", json=body).json()

    # ── Health ─────────────────────────────────────────────────────────

    def get_frontier_health(
        self,
        frontier_id: str,
        *,
        days: int = 30,
    ) -> dict[str, Any]:
        """Compute live GEC health from recent efficiency events for a frontier.

        Parameters
        ----------
        frontier_id : str
            The frontier to query.
        days : int
            Lookback window (1–90, default 30).

        Returns
        -------
        dict
            ``{"frontier_id": ..., "current_gec0": ..., "avg_gec": ...,
            "trend": ..., "metallic_label": ..., "ci": {...},
            "csk_health": {...}, "attractor": {...}, "n": ..., "days": ...,
            "frontier_c_max": ..., "updated_at": ...}``.
        """
        params: dict[str, str] = {}
        if days != 30:
            params["days"] = str(days)
        return self._t.get(
            f"{PREFIX}/frontiers/{frontier_id}/health", params=params
        ).json()

    # ── Custom Frontier Calibration ──────────────────────────────────

    _CONSOLE_PREFIX = "/internal/project/frontiers/custom"

    def start_calibration(self, frontier_id: str) -> dict[str, Any]:
        """Begin calibration for a custom frontier.

        Transitions the frontier from ``draft`` to ``calibrating``. The
        caller should then submit attestations through normal API usage
        and call :meth:`complete_calibration` once enough samples exist.

        Parameters
        ----------
        frontier_id : str
            UUID of the custom frontier.

        Returns
        -------
        dict
            ``{"custom_frontier": {...}, "instructions": "..."}``.
        """
        return self._t.post(
            f"{self._CONSOLE_PREFIX}/{frontier_id}/calibrate/start"
        ).json()

    def complete_calibration(self, frontier_id: str) -> dict[str, Any]:
        """Attempt to complete calibration and auto-activate the frontier.

        Queries accumulated ``efficiency_events`` to determine measured
        ``c_max`` and confidence interval.  If calibration thresholds
        pass, the frontier transitions to ``active`` automatically.

        Parameters
        ----------
        frontier_id : str
            UUID of the custom frontier.

        Returns
        -------
        dict
            If successful: ``{"state": "active", "measured": {...}, "custom_frontier": {...}}``.
            If not ready: ``{"state": "calibrating", "reason": [...], "current": {...}}``.
        """
        return self._t.post(
            f"{self._CONSOLE_PREFIX}/{frontier_id}/calibrate/complete"
        ).json()

    def calibrate_frontier(
        self,
        frontier_id: str,
        workflow_fn: "Any",
        *,
        n: int = 30,
        submit_fn: "Any | None" = None,
    ) -> dict[str, Any]:
        """End-to-end calibration: start, run workflow N times, complete.

        Parameters
        ----------
        frontier_id : str
            UUID of the custom frontier.
        workflow_fn : callable
            Function that runs one iteration of the workflow.
            Should return a dict with ``y`` (yield) and ``x`` (resource).
        n : int
            Number of calibration iterations (default 30).
        submit_fn : callable, optional
            Custom function to submit attestation results. If not provided,
            ``workflow_fn`` results are assumed to be submitted via normal
            API key usage.

        Returns
        -------
        dict
            Result of ``complete_calibration``.
        """
        self.start_calibration(frontier_id)

        for _i in range(n):
            result = workflow_fn()
            if submit_fn is not None and result is not None:
                submit_fn(result)

        return self.complete_calibration(frontier_id)

    def suspend_frontier(self, frontier_id: str) -> dict[str, Any]:
        """Suspend an active custom frontier (halt).

        Parameters
        ----------
        frontier_id : str
            UUID of the custom frontier.
        """
        return self._t.post(
            f"{self._CONSOLE_PREFIX}/{frontier_id}/suspend"
        ).json()

    def unsuspend_frontier(self, frontier_id: str) -> dict[str, Any]:
        """Re-activate a suspended custom frontier.

        Parameters
        ----------
        frontier_id : str
            UUID of the custom frontier.
        """
        return self._t.post(
            f"{self._CONSOLE_PREFIX}/{frontier_id}/unsuspend"
        ).json()
