"""GET /api/system-status — single source of truth for chrome status surfaces.

Law 12 substrate: every value the chrome shows about system health derives
from this endpoint. No fixture literals in Titlebar / StatusBar / StatusPopover
/ BottomBay after Phase 4.

Anti-Pattern 4 note: SystemStatus + WorkerPoolCounts are Pydantic shapes whose
TS twin is codegen'd into @recoil/contracts/src/generated.ts. They are
re-exported from `recoil/api/schemas/engine.py` (the codegen module entry
point) so pydantic2ts picks them up alongside the other engine entities. Any
hand-typed `interface SystemStatus` on the TS side is a violation.

Anti-Pattern 5 note: this module deliberately stays as ONE file (~80 lines,
three public symbols). Splitting into routes.py + model.py + worker_counts.py
buys nothing but indirection.
"""

from __future__ import annotations

import os
import time

from fastapi import APIRouter
from pydantic import BaseModel, ConfigDict, Field

from recoil.api.schemas._base import SCHEMA_VERSION, _Versioned

router = APIRouter()

_PROCESS_START = time.monotonic()
_API_VERSION = os.environ.get("RECOIL_API_VERSION", "v2.0.1")


class WorkerPoolCounts(BaseModel):
    """Per-pool active/capacity counts.

    Today: every value is 0 because the queue is fixture-only. The endpoint
    raises 503 (Phase 5 Site 8) until the workers subsystem is wired to a
    real queue tracker, so this dataclass is reserved for the response_model
    schema documentation only.
    """

    model_config = ConfigDict(populate_by_name=True, frozen=True)
    veo_active: int = Field(default=0, alias="veoActive")
    veo_capacity: int = Field(default=0, alias="veoCapacity")
    imagen_active: int = Field(default=0, alias="imagenActive")
    imagen_capacity: int = Field(default=0, alias="imagenCapacity")
    elevenlabs_active: int = Field(default=0, alias="elevenlabsActive")
    elevenlabs_capacity: int = Field(default=0, alias="elevenlabsCapacity")


class SystemStatus(_Versioned):
    """Chrome status snapshot. All values derived from API process state.

    Phase-21-22 Phase 5 (CP-D scrub Site 8): the synthesized-workers /
    synthesized-spend fields were retired. Until queue tracker + ledger are
    wired, the endpoint raises 503; the frontend infers degraded status
    from the absence of the workers field rather than from a synthesized
    flag.

    `fallback_counts` is filtered to names with count>0 to keep the response
    small. Operator can call `list_sanctioned_fallbacks()` from
    `recoil.pipeline._lib.sanctioned_fallbacks` for the closed name set.
    """

    host: str = Field(..., description="bind host:port the API is listening on")
    api_version: str = Field(..., alias="apiVersion")
    uptime_seconds: float = Field(..., alias="uptimeSeconds")
    workers: WorkerPoolCounts
    spend_today_usd: float = Field(
        default=0.0,
        alias="spendTodayUsd",
        description="today's API spend; 0.0 until ledger wired",
    )
    spend_synthesized: bool = Field(
        default=True,
        alias="spendSynthesized",
        description="True until ledger wired",
    )
    fallback_counts: dict[str, int] = Field(
        default_factory=dict, alias="fallbackCounts"
    )


@router.get("/system-status", response_model=SystemStatus)
async def get_system_status() -> SystemStatus:
    # 2026-05-11: previously raised 503 to indicate the workers subsystem isn't
    # wired. That caused Chrome to log a red error on every 5s poll, drowning
    # the devtools console in noise that wasn't actionable (the API process IS
    # reachable; only the subsystem is missing). Returning 200 with zeroed
    # worker counts + `spend_synthesized=True` lets the frontend infer the
    # degraded state from the payload shape (zero capacity → not wired) without
    # polluting the console. useSystemStatus's degraded503 branch stays in
    # place for any future endpoint that truly should 503.
    host = os.environ.get("RECOIL_API_HOST", "0.0.0.0:8431")
    return SystemStatus(
        schema_version=SCHEMA_VERSION,
        host=host,
        api_version=_API_VERSION,
        uptime_seconds=time.monotonic() - _PROCESS_START,
        workers=WorkerPoolCounts(),
        spend_today_usd=0.0,
        spend_synthesized=True,
        fallback_counts={},
    )


__all__ = ["SystemStatus", "WorkerPoolCounts", "router"]
