from pydantic import BaseModel, Field
from datetime import datetime
from uuid import uuid4
from typing import Any


class DecisionReceiptModel(BaseModel):
    """Immutable Decision Receipt — records every agent decision.

    Enterprise-grade audit record. Each field answers a compliance question:
      - who      → user_id, source_agent_id, cloud_user_email_hash
      - when     → created_at
      - what     → receipt_type, memories_accessed/created
      - where    → org_id, project_hash, ide (VS Code / Cursor / Desktop)
      - why      → intent (why the agent thought this memory was relevant)
      - how      → arbitration_result, context_hash
      - impact   → risk_score (0.0-1.0), pii_touched, classification
      - proof    → merkle_hash chain
    """
    id: str = Field(default_factory=lambda: str(uuid4()))
    session_id: str | None = None
    user_id: str | None = None
    org_id: str | None = None
    receipt_type: str  # query / store / promote / arbitrate / decrypt / annihilate
    memories_accessed: list[str] = []
    memories_created: list[str] = []
    arbitration_result: dict[str, Any] | None = None
    context_hash: str | None = None
    response_hash: str | None = None
    merkle_hash: str = ""
    prev_merkle_hash: str | None = None
    metadata: dict[str, Any] = {}
    # Cross-Agent Protocol fields (v0.4.0)
    source_agent_id: str | None = None
    target_agent_id: str | None = None
    cross_agent_ref: str | None = None  # receipt_id from peer agent
    # Enterprise audit enrichment (v0.5.0)
    intent: str | None = None  # Natural-language "why this decision"
    data_lineage: list[str] = []  # Ordered list of memory IDs that fed into this decision
    risk_score: float = 0.0  # 0.0-1.0 — computed from PII + classification + cross-org
    pii_touched: list[str] = []  # Types of PII involved (email, ssn, etc.)
    compliance_tags: list[str] = []  # e.g. ["GDPR-Art-17-applies", "HIPAA-PHI"]
    project_hash: str | None = None  # Which project's scope
    ide: str | None = None  # vscode / cursor / windsurf / desktop / browser
    cloud_user_id: str | None = None  # Cloud SOAGILA user ID if signed in
    cloud_email_hash: str | None = None  # SHA-256 of email for anonymized audit
    created_at: datetime = Field(default_factory=datetime.utcnow)

    def to_display_dict(self) -> dict:
        """Formatted dict for dashboard display."""
        return {
            "id": self.id,
            "type": self.receipt_type,
            "time": self.created_at.strftime("%Y-%m-%d %H:%M:%S"),
            "user_id": self.user_id,
            "cloud_user_id": self.cloud_user_id,
            "ide": self.ide,
            "project_hash": self.project_hash,
            "intent": self.intent,
            "memories_accessed_count": len(self.memories_accessed),
            "memories_created_count": len(self.memories_created),
            "data_lineage_depth": len(self.data_lineage),
            "risk_score": round(self.risk_score, 3),
            "pii_touched": self.pii_touched,
            "compliance_tags": self.compliance_tags,
            "merkle_hash_short": self.merkle_hash[:16] + "..." if self.merkle_hash else "",
            "has_arbitration": self.arbitration_result is not None,
            "source_agent_id": self.source_agent_id,
            "target_agent_id": self.target_agent_id,
            "cross_agent_ref": self.cross_agent_ref,
        }

    def compute_risk_score(self) -> float:
        """Deterministic risk score from PII + classification + cross-org signals."""
        score = 0.0
        # PII presence
        high_pii = {"ssn", "credit_card", "passport", "national_id"}
        mid_pii = {"email", "phone", "address", "dob"}
        for p in self.pii_touched:
            if p.lower() in high_pii:
                score = max(score, 0.8)
            elif p.lower() in mid_pii:
                score = max(score, 0.4)
            else:
                score = max(score, 0.2)

        # Cross-agent = higher risk (data crossed trust boundary)
        if self.cross_agent_ref:
            score = min(1.0, score + 0.2)

        # Classification bumps
        cls = (self.metadata or {}).get("classification", "")
        if cls in ("financial", "medical"):
            score = min(1.0, score + 0.2)

        return round(score, 3)
