# SPDX-License-Identifier: Apache-2.0
"""Gate: the one function.

gate(text) → GateResult

Text in, verdict + receipt + claims + violations out.
This is the entire kernel surface for checking agent output.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from .anchors import Anchor, Violation, check_text
from .claims import Claim, STATUS_CONTESTED, extract_claims
from .contradictions import find_contradictions
from .receipt import Receipt, create_receipt, VERDICT_PASS, VERDICT_WARN, VERDICT_BLOCK
from .resolver import resolve_verdict


@dataclass(frozen=True)
class GateResult:
    """Result of gating agent output.

    verdict: "pass", "warn", or "block".
    receipt: Content-addressed proof of this decision.
    claims: Claims extracted from the text.
    violations: Anchor violations found.
    """

    verdict: str
    receipt: Receipt
    claims: list[Claim]
    violations: list[Violation]

    @property
    def contested_claims(self) -> list[Claim]:
        """Claims with status CONTESTED (contradictions detected)."""
        return [c for c in self.claims if c.status == STATUS_CONTESTED]

    def to_dict(self) -> dict[str, Any]:
        return {
            "verdict": self.verdict,
            "receipt": self.receipt.to_dict(),
            "claims": [c.to_dict() for c in self.claims],
            "violations": [v.to_dict() for v in self.violations],
        }

    @classmethod
    def from_dict(cls, d: dict[str, Any]) -> GateResult:
        return cls(
            verdict=d["verdict"],
            receipt=Receipt.from_dict(d["receipt"]),
            claims=[Claim.from_dict(c) for c in d["claims"]],
            violations=[Violation.from_dict(v) for v in d["violations"]],
        )


def gate(
    text: str,
    *,
    anchors: list[Anchor] | None = None,
    prior_claims: list[Claim] | None = None,
) -> GateResult:
    """Gate agent output: extract claims, check anchors, produce receipt.

    Args:
        text: The agent output to check.
        anchors: Optional list of Anchor constraints. If None, only
                 claim extraction is performed (verdict will be "pass"
                 unless claims themselves trigger warnings).
        prior_claims: Optional list of prior Claims to check for
                      contradictions. Only SUPPORTED and CONTESTED priors
                      trigger contradiction detection.

    Returns:
        GateResult with verdict, receipt, claims, and violations.
    """
    # 1. Extract claims
    claims = extract_claims(text)

    # 2. Check anchors
    violations = check_text(text, anchors or [])

    # 3. Find contradictions against prior_claims
    if prior_claims:
        claims = find_contradictions(claims, prior_claims)

    # 4. Determine verdict from violations
    # Note: contradictions don't block — they CONTEST claims (epistemic, not policy)
    verdict = resolve_verdict(violations)

    # 5. Build evidence for receipt — hash the state, not the statistic
    evidence: dict[str, Any] = {
        "claims": [c.to_dict() for c in claims],
        "violations_count": len(violations),
        "anchor_count": len(anchors) if anchors else 0,
        "prior_claims_count": len(prior_claims) if prior_claims else 0,
    }

    # 6. Create content-addressed receipt
    receipt = create_receipt(
        gate="nlai_gate",
        verdict=verdict,
        subject_kind="text",
        subject_bytes=text.encode("utf-8"),
        evidence=evidence,
    )

    return GateResult(
        verdict=verdict,
        receipt=receipt,
        claims=claims,
        violations=violations,
    )
