"""Normalized case object — the contract between every worker line."""

from __future__ import annotations

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

from pydantic import BaseModel, Field


def utcnow() -> datetime:
    return datetime.now(timezone.utc)


class TLP(str, Enum):
    RED = "RED"
    AMBER = "AMBER"
    GREEN = "GREEN"
    CLEAR = "CLEAR"


class Severity(str, Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


class InternalClass(str, Enum):
    A = "A"
    B = "B"
    C = "C"
    D = "D"
    E = "E"


class IncidentType(str, Enum):
    ACCESS_SALE = "access_sale"
    RANSOMWARE = "ransomware"
    CREDENTIAL_LEAK = "credential_leak"
    PHISHING = "phishing"
    MALWARE = "malware"
    EXPLOIT = "exploit"
    BOTNET = "botnet"
    DATA_LEAK = "data_leak"


class Classification(BaseModel):
    internal_class: Optional[InternalClass] = None
    severity: Optional[Severity] = None
    tlp: TLP = TLP.AMBER
    incident_type: Optional[IncidentType] = None


class Confidence(BaseModel):
    level: str = "low"  # low | medium | high
    source_reliability: str = "unknown"  # Admiralty A-F
    information_credibility: str = "unknown"  # Admiralty 1-6
    freshness: str = "unknown"  # new | recent | stale | resurfaced
    iocs_valid: bool = True


class Victim(BaseModel):
    name: str = ""
    domain: str = ""
    country: str = ""
    sector: str = ""
    critical_infrastructure: bool = False


class Actor(BaseModel):
    name: str = ""
    aliases: List[str] = Field(default_factory=list)
    campaign: str = ""
    confidence: str = "low"


class Observables(BaseModel):
    domains: List[str] = Field(default_factory=list)
    ips: List[str] = Field(default_factory=list)
    urls: List[str] = Field(default_factory=list)
    hashes: List[str] = Field(default_factory=list)
    cves: List[str] = Field(default_factory=list)
    wallets: List[str] = Field(default_factory=list)
    emails: List[str] = Field(default_factory=list)


class Evidence(BaseModel):
    raw_evidence_location: str = ""
    sealed_package_id: str = ""
    payload_hash: str = ""
    plaintext_destroyed: bool = False
    local_unwrapped_key_destroyed: bool = False


class Routing(BaseModel):
    recommended_routes: List[str] = Field(default_factory=list)
    blocked_routes: List[str] = Field(default_factory=list)
    human_approval_required: bool = True


class Case(BaseModel):
    case_id: str = Field(default_factory=lambda: f"PSYC-{uuid4().hex[:12].upper()}")
    summary: str = ""
    source_type: str = ""
    source_ref: str = ""
    source_metadata: Dict[str, str] = Field(default_factory=dict)
    observed_at: datetime = Field(default_factory=utcnow)
    ingested_at: datetime = Field(default_factory=utcnow)
    classification: Classification = Field(default_factory=Classification)
    confidence: Confidence = Field(default_factory=Confidence)
    victim: Victim = Field(default_factory=Victim)
    actor: Actor = Field(default_factory=Actor)
    observables: Observables = Field(default_factory=Observables)
    evidence: Evidence = Field(default_factory=Evidence)
    routing: Routing = Field(default_factory=Routing)


class SealedPackage(BaseModel):
    package_id: str
    created_at: datetime
    plaintext_hash: str
    recipients: List[str] = Field(default_factory=list)
    ciphertext_per_recipient: Dict[str, str] = Field(default_factory=dict)
    metadata: Dict[str, str] = Field(default_factory=dict)


class Outcome(str, Enum):
    SUBMITTED = "submitted"
    ACKNOWLEDGED = "acknowledged"
    REJECTED = "rejected"
    ACTIONED = "actioned"
    FAILED = "failed"
    PENDING_APPROVAL = "pending_approval"


class LedgerEntry(BaseModel):
    id: int
    timestamp: datetime
    case_id: str
    destination: str
    payload_hash: str
    submitter_identity: str
    tlp: TLP
    response_id: Optional[str] = None
    outcome: Outcome
    detail: Optional[str] = None


class ApprovalStatus(str, Enum):
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"


class PendingSubmission(BaseModel):
    id: Optional[int] = None
    case_id: str
    destination_name: str
    payload_kind: str
    payload_hash: str
    payload_json: str  # frozen payload — what will be sent on approval
    tlp: TLP
    created_at: datetime
    status: ApprovalStatus = ApprovalStatus.PENDING
    reviewer: Optional[str] = None
    reviewed_at: Optional[datetime] = None
    reason: Optional[str] = None


class ActionType(str, Enum):
    ALERT = "alert"          # notify the SOC (webhook/Slack)
    BLOCKLIST = "blocklist"  # push IOCs to firewall/DNS enforcement
    TICKET = "ticket"        # open an incident ticket


class ActionStatus(str, Enum):
    PROPOSED = "proposed"    # generated, awaiting human approval
    EXECUTED = "executed"    # approved + fired successfully
    REJECTED = "rejected"    # human declined; nothing fired
    FAILED = "failed"        # approved but execution errored


class ResponseAction(BaseModel):
    id: Optional[int] = None
    case_id: str
    action_type: ActionType
    target: str               # enforcement target label
    summary: str              # human-readable "what this does"
    payload_json: str         # frozen payload sent on execution
    severity: Optional[str] = None
    status: ActionStatus = ActionStatus.PROPOSED
    created_at: datetime
    approver: Optional[str] = None
    executed_at: Optional[datetime] = None
    detail: Optional[str] = None
