"""Declarative quality gates evaluated against extraction stats."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Literal

from .schema import StatsRecord


@dataclass
class GateResult:
    name: str
    passed: bool
    severity: Literal["warn", "fail"]
    actual: float
    threshold: float
    message: str


class QualityGates:
    """Evaluate a set of quality assertions against a StatsRecord."""

    def __init__(self, config: dict[str, Any]) -> None:
        self._config = config

    def evaluate(self, stats: StatsRecord) -> list[GateResult]:
        results: list[GateResult] = []
        cfg = self._config

        # min_elements: total_elements >= threshold
        if "min_elements" in cfg:
            g = cfg["min_elements"]
            threshold = float(g.get("threshold", 1))
            actual = float(stats.total_elements)
            severity = g.get("severity", "fail")
            passed = actual >= threshold
            results.append(
                GateResult(
                    name="min_elements",
                    passed=passed,
                    severity=severity,
                    actual=actual,
                    threshold=threshold,
                    message=f"total_elements {actual:.0f} < {threshold:.0f}"
                    if not passed
                    else "ok",
                )
            )

        # min_confidence_p10: confidence.p10 >= threshold
        if "min_confidence_p10" in cfg and stats.confidence is not None:
            g = cfg["min_confidence_p10"]
            threshold = float(g.get("threshold", 0.0))
            actual = float(stats.confidence.p10)
            severity = g.get("severity", "warn")
            passed = actual >= threshold
            results.append(
                GateResult(
                    name="min_confidence_p10",
                    passed=passed,
                    severity=severity,
                    actual=actual,
                    threshold=threshold,
                    message=f"confidence p10 {actual:.2f} < {threshold:.2f}"
                    if not passed
                    else "ok",
                )
            )

        # max_empty_ratio: empty text elements / total <= threshold
        if "max_empty_ratio" in cfg:
            g = cfg["max_empty_ratio"]
            threshold = float(g.get("threshold", 1.0))
            empty = stats.elements_by_type.get("structural:empty", 0)
            total = max(stats.total_elements, 1)
            actual = empty / total
            severity = g.get("severity", "warn")
            passed = actual <= threshold
            results.append(
                GateResult(
                    name="max_empty_ratio",
                    passed=passed,
                    severity=severity,
                    actual=actual,
                    threshold=threshold,
                    message=f"empty ratio {actual:.2%} > {threshold:.2%}" if not passed else "ok",
                )
            )

        # max_table_continuation_ratio: table:continuation / total <= threshold
        if "max_table_continuation_ratio" in cfg:
            g = cfg["max_table_continuation_ratio"]
            threshold = float(g.get("threshold", 1.0))
            cont = stats.elements_by_type.get("table:continuation", 0)
            total = max(stats.total_elements, 1)
            actual = cont / total
            severity = g.get("severity", "warn")
            passed = actual <= threshold
            results.append(
                GateResult(
                    name="max_table_continuation_ratio",
                    passed=passed,
                    severity=severity,
                    actual=actual,
                    threshold=threshold,
                    message=f"table continuation ratio {actual:.2%} > {threshold:.2%}"
                    if not passed
                    else "ok",
                )
            )

        return results

    def has_failures(self, results: list[GateResult]) -> bool:
        return any(not r.passed and r.severity == "fail" for r in results)
