"""
SDK Metrics

Lightweight pipeline latency and throughput tracking.
Prometheus-compatible histogram and counter implementations.
"""

from __future__ import annotations

import math
import time
from typing import Callable

from dvgateway.types import Logger


class Histogram:
    """Fixed-bucket histogram for latency measurements."""

    def __init__(self, buckets: list[float] | None = None) -> None:
        self._buckets = sorted(buckets or [10, 50, 100, 200, 500, 1000, 2000, 5000])
        self._counts = [0] * (len(self._buckets) + 1)
        self._sum = 0.0
        self._count = 0

    def observe(self, value: float) -> None:
        self._sum += value
        self._count += 1

        placed = False
        for i, bucket in enumerate(self._buckets):
            if value <= bucket:
                self._counts[i] += 1
                placed = True
                break
        if not placed:
            self._counts[-1] += 1

    def percentiles(self) -> dict[str, float]:
        """Returns p50, p95, p99, mean in ms."""
        if self._count == 0:
            return {"p50": 0.0, "p95": 0.0, "p99": 0.0, "mean": 0.0}
        return {
            "p50": self._percentile(0.50),
            "p95": self._percentile(0.95),
            "p99": self._percentile(0.99),
            "mean": self._sum / self._count,
        }

    def _percentile(self, p: float) -> float:
        target = math.ceil(p * self._count)
        cumulative = 0
        for i, bucket in enumerate(self._buckets):
            cumulative += self._counts[i]
            if cumulative >= target:
                return bucket
        return self._buckets[-1] if self._buckets else 0.0

    def to_prometheus(self, name: str, labels: dict[str, str] | None = None) -> str:
        label_str = ",".join(f'{k}="{v}"' for k, v in (labels or {}).items())
        l_suffix = f"{{{label_str}}}" if label_str else ""
        lines: list[str] = []

        cumulative = 0
        for i, bucket in enumerate(self._buckets):
            cumulative += self._counts[i]
            bucket_label = f'{{{label_str},le="{bucket}"}}' if label_str else f'{{le="{bucket}"}}'
            lines.append(f"{name}_bucket{bucket_label} {cumulative}")
        cumulative += self._counts[-1]
        inf_label = f'{{{label_str},le="+Inf"}}' if label_str else '{le="+Inf"}'
        lines.append(f"{name}_bucket{inf_label} {cumulative}")
        lines.append(f"{name}_sum{l_suffix} {self._sum}")
        lines.append(f"{name}_count{l_suffix} {self._count}")
        return "\n".join(lines)


class Counter:
    """Simple increment/reset counter."""

    def __init__(self) -> None:
        self._value = 0

    def increment(self, by: int = 1) -> None:
        self._value += by

    def get(self) -> int:
        return self._value

    def reset(self) -> None:
        self._value = 0


class PipelineMetrics:
    """Pipeline latency and throughput tracking with Prometheus export."""

    def __init__(self, logger: Logger) -> None:
        self._logger = logger
        self.stt_latency = Histogram([50, 100, 200, 500, 1000, 2000])
        self.llm_ttft = Histogram([20, 50, 80, 120, 200, 500, 1000])
        self.tts_latency = Histogram([50, 100, 150, 300, 500, 1000])
        self.e2e_latency = Histogram([100, 200, 300, 500, 700, 1000, 2000])

        self.transcripts_total = Counter()
        self.tts_injections_total = Counter()
        self.errors_total = Counter()
        self.active_calls = Counter()

    def start_timer(self) -> Callable[[], float]:
        """Start a latency measurement; returns a function to stop it."""
        start = time.monotonic()
        return lambda: (time.monotonic() - start) * 1000  # ms

    def log_summary(self) -> None:
        stt = self.stt_latency.percentiles()
        llm = self.llm_ttft.percentiles()
        tts = self.tts_latency.percentiles()
        e2e = self.e2e_latency.percentiles()

        self._logger.info(
            {
                "stt_p50_ms": stt["p50"], "stt_p95_ms": stt["p95"],
                "llm_ttft_p50_ms": llm["p50"], "llm_ttft_p95_ms": llm["p95"],
                "tts_p50_ms": tts["p50"], "tts_p95_ms": tts["p95"],
                "e2e_p50_ms": e2e["p50"], "e2e_p95_ms": e2e["p95"],
                "transcripts": self.transcripts_total.get(),
                "tts_injections": self.tts_injections_total.get(),
                "errors": self.errors_total.get(),
            },
            "DVGateway SDK metrics summary",
        )

    def to_prometheus(self) -> str:
        return "\n".join([
            self.stt_latency.to_prometheus("dvgw_stt_latency_ms"),
            self.llm_ttft.to_prometheus("dvgw_llm_ttft_ms"),
            self.tts_latency.to_prometheus("dvgw_tts_latency_ms"),
            self.e2e_latency.to_prometheus("dvgw_e2e_latency_ms"),
            f"dvgw_transcripts_total {self.transcripts_total.get()}",
            f"dvgw_tts_injections_total {self.tts_injections_total.get()}",
            f"dvgw_errors_total {self.errors_total.get()}",
            f"dvgw_active_calls {self.active_calls.get()}",
        ])
