"""
common/worker_metrics.py — Prometheus metrics for pool workers (operator 2026-06-19).

Exposed via each worker's /metrics endpoint; the scrape target (Prometheus `instance`
label) distinguishes the box, so the metrics themselves stay low-cardinality.

  - forward_pass_window_seconds : time to compute ONE fresh forward-pass window (the
        "first pass" — resumed/cached windows are NOT timed). The raw signal the recovery
        timing model T(N)=a*N^k is built from, and the per-window Grafana latency.
  - worker_job_seconds          : end-to-end time to process one task, by stage ("time
        per job" for every other service).

FAIL-SAFE (audit rule #2): prometheus_client is OPTIONAL here. If it is absent from a
worker image, this module degrades to no-op metrics rather than raising on import — an
optional-observability dependency must NEVER break the worker's real work (2026-06-19:
a hard import here error-looped every forward_pass).
"""
from __future__ import annotations

try:
    from prometheus_client import (
        CollectorRegistry, Histogram, generate_latest, CONTENT_TYPE_LATEST,
    )
    _HAVE_PROM = True
except Exception:
    _HAVE_PROM = False


if _HAVE_PROM:
    REGISTRY = CollectorRegistry()

    FORWARD_PASS_WINDOW_SECONDS = Histogram(
        "forward_pass_window_seconds",
        "Seconds to compute one FRESH forward-pass window (excludes resume/cache hits).",
        buckets=(30, 60, 120, 300, 600, 1200, 1800, 2700, 3600, 5400, 7200),
        registry=REGISTRY,
    )
    WORKER_JOB_SECONDS = Histogram(
        "worker_job_seconds",
        "Seconds to process one task end-to-end, by stage.",
        ("stage",),
        buckets=(1, 5, 15, 60, 180, 600, 1800, 3600, 7200, 21600, 43200),
        registry=REGISTRY,
    )

    def render() -> tuple[bytes, str]:
        """(_body, content_type) for a worker's GET /metrics handler."""
        return generate_latest(REGISTRY), CONTENT_TYPE_LATEST

else:
    class _Noop:
        """No-op metric — workers without prometheus_client still run (metrics absent)."""
        def observe(self, *a, **k): pass
        def labels(self, *a, **k):  return self

    FORWARD_PASS_WINDOW_SECONDS = _Noop()
    WORKER_JOB_SECONDS          = _Noop()

    def render() -> tuple[bytes, str]:
        return (b"# prometheus_client not installed; worker metrics disabled\n",
                "text/plain; charset=utf-8")
