from __future__ import annotations

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

from receipts.compat.pyd import Field, model_validator
from receipts.base import BaseReceipt
from receipts.domains.governance import GovernanceReceipt


class Capability(BaseReceipt):
    """
    Normalized capability schema for UPCP.
    """

    receipt_type: Literal["Capability"] = Field(default="Capability")
    domain: Literal["governance"] = Field(default="governance")
    organ: str = Field(default="capability")

    resource: str
    action: str
    context: Dict[str, Any] = Field(default_factory=dict)


def normalize_capability(
    resource: str,
    action: str,
    context: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
    """
    Build a normalized capability payload for UPCP usage.

    - resource: coarse-grained target (e.g., "llm", "tool", "filesystem")
    - action: verb over that resource (e.g., "call", "run", "read", "write")
    - context: optional structured metadata (model, route, tool_name, path, etc.)
    """
    return {
        "resource": resource,
        "action": action,
        "context": context or {},
    }


class PermissionReceipt(GovernanceReceipt):
    """
    Canonical record of a capability check in the Loom substrate.
    """

    receipt_type: Literal["PermissionReceipt"] = Field(default="PermissionReceipt")
    domain: Literal["governance"] = Field(default="governance")
    organ: str = Field(default="permission_router")

    request_id: str
    requester: str
    capability: Dict[str, Any]
    decision: Literal["allow", "deny", "defer"]
    reason: str
    ts: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
    parent_ids: List[str] = Field(default_factory=list)
    branch: str = "main"
    receipt_id: str = Field(default_factory=lambda: f"perm-{uuid.uuid4()}")
    # CRIF signature (Contradiction, Recursion, Incompleteness, Flow), bounded [0,1]
    crif: Optional[Dict[str, float]] = Field(default=None)

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for serialization."""
        data = super().to_dict()
        # Ensure new fields are present explicitly
        data["profile"] = self.profile
        data["receipt_mode"] = self.receipt_mode
        data["retention_days"] = self.retention_days
        data["encryption_required"] = self.encryption_required
        return data

    @model_validator(mode="before")
    @classmethod
    def _default_crif(cls, data: Any) -> Any:
        """Populate a simple CRIF signature based on decision when missing."""
        if not isinstance(data, dict):
            return data
        payload = dict(data)
        if payload.get("crif") is None and payload.get("decision"):
            decision = str(payload.get("decision")).lower()
            if decision == "allow":
                payload["crif"] = {"C": 0.0, "R": 0.0, "I": 0.0, "F": 1.0}
            else:
                payload["crif"] = {"C": 1.0, "R": 0.0, "I": 0.0, "F": 0.0}
        return payload
