"""
GuardianVerdictReceipt: Full receipt for Guardian gate decisions.

Implements Claim 15 requirements:
- Matched policy references
- Computed dignity facet scores
- Final verdict with reasoning

The Guardian gate is the constitutional enforcement point that checks
all actions against dignity floors and policy constraints.
"""
from __future__ import annotations

from datetime import datetime, timezone
from typing import Any, Dict, List, Literal, Optional

from receipts.compat.pyd import BaseModel, Field, field_validator, model_validator
from receipts.base import BaseReceipt, Domain


class DignityFacetScore(BaseModel):
    """
    Individual dignity facet score with reasoning.

    The multi-facet dignity model evaluates actions across dimensions:
    - autonomy: Respects agent/user self-determination
    - privacy: Protects personal information
    - fairness: Treats all parties equitably
    - transparency: Actions are explainable
    - consent: Appropriate permissions obtained

    Note: This is a plain Pydantic model (not a receipt) because it's
    embedded within GuardianVerdictReceipt, not stored independently.
    """

    facet: Literal["autonomy", "privacy", "fairness", "transparency", "consent"] = Field(
        ...,
        description="Which dignity dimension this score represents",
    )
    score: float = Field(
        ...,
        ge=0.0,
        le=1.0,
        description="Score for this facet (0=violation, 1=exemplary)",
    )
    weight: float = Field(
        default=1.0,
        ge=0.0,
        description="Weight of this facet in composite score",
    )
    reasoning: Optional[str] = Field(
        default=None,
        description="Why this score was assigned",
    )


class GuardianVerdictReceipt(BaseReceipt):
    """
    Full receipt documenting a Guardian gate decision.

    Every action that passes through the Guardian gate produces this receipt,
    whether approved or denied. This creates an audit trail of all
    constitutional enforcement decisions.
    """

    receipt_type: str = Field(default="GuardianVerdictReceipt")
    domain: str = Field(default=Domain.GOVERNANCE.value)

    # Action being evaluated
    action: str = Field(
        ...,
        description="Action class being evaluated (e.g., 'fs.write', 'shell.exec')",
    )
    action_target: Optional[str] = Field(
        default=None,
        description="Target of the action",
    )
    agent_id: str = Field(
        ...,
        description="Agent requesting the action",
    )

    # Policy matching (Claim 15)
    matched_policies: List[str] = Field(
        default_factory=list,
        description="Policy IDs that matched this action",
    )
    policy_version: Optional[str] = Field(
        default=None,
        description="Version of policy used for evaluation",
    )

    # Dignity evaluation (Claim 15)
    dignity_facet_scores: List[DignityFacetScore] = Field(
        default_factory=list,
        description="Individual facet scores",
    )
    dignity_composite: float = Field(
        ...,
        ge=0.0,
        le=1.0,
        description="Weighted composite dignity score",
    )
    dignity_floor: float = Field(
        default=0.15,
        ge=0.0,
        le=1.0,
        description="Dignity floor threshold in effect",
    )
    dignity_floor_violated: bool = Field(
        default=False,
        description="Whether action violated the dignity floor",
    )

    # Verdict
    verdict: Literal["ALLOW", "DENY", "DEFER"] = Field(
        ...,
        description="Final Guardian decision",
    )
    verdict_reason: str = Field(
        ...,
        description="Human-readable explanation of verdict",
    )
    verdict_code: Optional[str] = Field(
        default=None,
        description="Machine-readable verdict code",
    )

    # Blocking details (if denied)
    blocking_rule: Optional[str] = Field(
        default=None,
        description="Which rule triggered the denial",
    )
    blocking_facet: Optional[str] = Field(
        default=None,
        description="Which dignity facet was primary blocker",
    )

    # Escalation (if deferred)
    escalation_path: Optional[Literal["human", "council", "timeout"]] = Field(
        default=None,
        description="Where deferred decisions are escalated",
    )
    escalation_reason: Optional[str] = Field(
        default=None,
        description="Why escalation is needed",
    )

    # Context
    capability_id: Optional[str] = Field(
        default=None,
        description="Capability receipt if action was authorized by permit",
    )
    episode_id: Optional[str] = Field(
        default=None,
        description="Episode this verdict belongs to",
    )

    @model_validator(mode="after")
    def _validate_verdict_consistency(self) -> "GuardianVerdictReceipt":
        """Ensure verdict fields are consistent."""
        if self.verdict == "DENY" and not self.blocking_rule:
            # Allow but warn - blocking_rule is recommended for denials
            pass
        if self.verdict == "DEFER" and not self.escalation_path:
            raise ValueError("DEFER verdict requires escalation_path")
        if self.dignity_floor_violated and self.verdict == "ALLOW":
            raise ValueError("Cannot ALLOW when dignity floor is violated")
        return self


def create_guardian_verdict(
    action: str,
    agent_id: str,
    verdict: str,
    verdict_reason: str,
    dignity_composite: float,
    dignity_floor: float = 0.15,
    **kwargs,
) -> GuardianVerdictReceipt:
    """Factory function to create a GuardianVerdictReceipt."""
    import uuid
    dignity_floor_violated = dignity_composite < dignity_floor

    return GuardianVerdictReceipt(
        receipt_id=f"gvr_{uuid.uuid4().hex[:16]}",
        action=action,
        agent_id=agent_id,
        verdict=verdict,
        verdict_reason=verdict_reason,
        dignity_composite=dignity_composite,
        dignity_floor=dignity_floor,
        dignity_floor_violated=dignity_floor_violated,
        **kwargs,
    )


__all__ = ["DignityFacetScore", "GuardianVerdictReceipt", "create_guardian_verdict"]
