"""
Guardian Verdict Receipts — Constitutional enforcement decisions.

Every Guardian decision (allow/deny) produces a receipt that:
- Is signed and chained (inherits from BaseReceipt)
- Captures the command, risk level, matched patterns
- Provides recourse for denied actions
- Links to parent receipts for chain verification

Schema: guardian_verdict.v1

This is the "event-level" receipt for Guardian decisions, analogous to
AgentActionReceipt but for the pre-execution vetting phase.
"""
from __future__ import annotations

import uuid
from datetime import datetime, timezone
from enum import Enum
from typing import Any, Dict, List, Literal, Optional

from receipts.compat.pyd import Field
from receipts.base import BaseReceipt, Domain


class RiskLevel(str, Enum):
    """Risk classification for commands."""
    LOW = "LOW"
    MEDIUM = "MEDIUM"
    HIGH = "HIGH"
    CRITICAL = "CRITICAL"


class GuardianVerdictReceipt(BaseReceipt):
    """
    Receipt for Guardian enforcement decisions.

    Emitted for every command vetting, whether allowed or denied.
    Provides complete audit trail of what was requested, how it was
    classified, and what decision was made.

    Invariants:
    - Every vetting request produces exactly one verdict receipt
    - CRITICAL denials MUST have matched_pattern and recourse
    - Latency should be < 50ms p99

    Example:
        {
            "receipt_type": "GuardianVerdictReceipt",
            "receipt_id": "gvr_593dff58c83b",
            "verdict_id": "v_d51f309a",
            "command": "rm -rf /",
            "allow": false,
            "risk_level": "CRITICAL",
            "matched_pattern": "filesystem_destruction",
            "reason": "Matches forbidden pattern: filesystem_destruction",
            "recourse": "Use capability token or get human approval",
            ...
        }

    Schema: guardian_verdict.v1
    """

    # Receipt metadata
    receipt_type: str = Field(default="GuardianVerdictReceipt")
    domain: str = Field(default=Domain.GOVERNANCE.value)
    schema_id: str = Field(default="guardian_verdict.v1")

    # Verdict identity
    verdict_id: str = Field(
        description="Unique ID for this verdict (e.g., v_d51f309a)"
    )

    # Request details
    action: str = Field(
        default="cli.exec",
        description="Action type (e.g., cli.exec, api.call)"
    )
    command: str = Field(
        description="The command or action that was vetted"
    )
    user: str = Field(
        default="developer",
        description="User/actor identity"
    )
    context: Dict[str, Any] = Field(
        default_factory=dict,
        description="Additional context from the request"
    )

    # Decision
    allow: bool = Field(
        description="Whether the action was allowed"
    )
    risk_level: RiskLevel = Field(
        description="Classified risk level (LOW/MEDIUM/HIGH/CRITICAL)"
    )

    # Classification details
    matched_pattern: Optional[str] = Field(
        default=None,
        description="Pattern tag that matched (e.g., 'filesystem_destruction')"
    )
    reason: Optional[str] = Field(
        default=None,
        description="Human-readable reason for the decision"
    )
    recourse: Optional[str] = Field(
        default=None,
        description="How to proceed if denied"
    )

    # Performance
    latency_ms: float = Field(
        default=0.0,
        description="Time taken to make the decision (ms)"
    )

    # Linking
    episode_id: Optional[str] = Field(
        default=None,
        description="Link to enclosing Episode (if any)"
    )
    execution_receipt_id: Optional[str] = Field(
        default=None,
        description="Link to resulting execution receipt (if allowed)"
    )

    @classmethod
    def create(
        cls,
        verdict_id: str,
        command: str,
        allow: bool,
        risk_level: RiskLevel,
        user: str = "developer",
        action: str = "cli.exec",
        matched_pattern: Optional[str] = None,
        reason: Optional[str] = None,
        recourse: Optional[str] = None,
        latency_ms: float = 0.0,
        parent_receipt_id: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> "GuardianVerdictReceipt":
        """Factory method to create a GuardianVerdictReceipt."""
        receipt_id = f"gvr_{uuid.uuid4().hex[:12]}"

        parent_ids = [parent_receipt_id] if parent_receipt_id else []

        return cls(
            receipt_id=receipt_id,
            verdict_id=verdict_id,
            command=command,
            user=user,
            action=action,
            allow=allow,
            risk_level=risk_level,
            matched_pattern=matched_pattern,
            reason=reason,
            recourse=recourse,
            latency_ms=latency_ms,
            parent_ids=parent_ids,
            context=context or {},
            valid_time=datetime.now(timezone.utc),
            allow_orphan=True,  # First verdict in a session has no parent
        )


class GuardianDenialEpisode(BaseReceipt):
    """
    Episode-level rollup of a denied action sequence.

    When Guardian denies multiple related actions (e.g., retries of
    the same dangerous command), this receipt aggregates them for
    analysis and alerting.

    Schema: guardian_denial_episode.v1
    """

    receipt_type: str = Field(default="GuardianDenialEpisode")
    domain: str = Field(default=Domain.GOVERNANCE.value)
    schema_id: str = Field(default="guardian_denial_episode.v1")

    # Episode details
    episode_id: str = Field(
        description="Unique episode ID"
    )
    verdict_ids: List[str] = Field(
        default_factory=list,
        description="List of verdict IDs in this episode"
    )
    denial_count: int = Field(
        default=0,
        description="Number of denials in this episode"
    )

    # Pattern analysis
    patterns_matched: List[str] = Field(
        default_factory=list,
        description="Unique patterns matched across all denials"
    )
    highest_risk: RiskLevel = Field(
        default=RiskLevel.LOW,
        description="Highest risk level seen in this episode"
    )

    # User context
    user: str = Field(
        default="developer",
        description="User who triggered the denials"
    )
    session_id: Optional[str] = Field(
        default=None,
        description="Session identifier"
    )

    # Time bounds
    first_denial_at: datetime = Field(
        default_factory=lambda: datetime.now(timezone.utc)
    )
    last_denial_at: datetime = Field(
        default_factory=lambda: datetime.now(timezone.utc)
    )


# Export all classes
__all__ = [
    "RiskLevel",
    "GuardianVerdictReceipt",
    "GuardianDenialEpisode",
]
