"""
SecurityAssessmentReceipt - Constitutional Security Event Tracking

Implements receipts for security assessments, CVE sweeps, and vulnerability
audits. Every security-relevant evaluation emits a receipt for:
- Audit trail / forensic lineage
- Proof of due diligence
- Constitutional compliance (security is a dignity concern)
"""
from __future__ import annotations

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

from pydantic import Field

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

logger = logging.getLogger(__name__)


# -----------------------------------------------------------------------------
# Enums
# -----------------------------------------------------------------------------

class VulnerabilityStatus(str, Enum):
    """Status of a vulnerability check for a specific CVE or security concern."""
    NOT_AFFECTED = "not_affected"  # No vulnerable components found
    AFFECTED = "affected"          # Vulnerable components found, unpatched
    MITIGATED = "mitigated"        # Vulnerable but mitigations applied
    PATCHED = "patched"            # Vulnerable components were patched
    UNKNOWN = "unknown"            # Unable to determine status


class AssessmentScope(str, Enum):
    """Scope of the security assessment."""
    FULL_SWEEP = "full_sweep"      # Complete codebase/infrastructure scan
    TARGETED = "targeted"          # Specific CVE or component check
    CONTINUOUS = "continuous"      # Ongoing monitoring assessment
    INCIDENT = "incident"          # Triggered by active incident


class SeverityLevel(str, Enum):
    """CVE severity classification."""
    CRITICAL = "critical"   # CVSS 9.0-10.0
    HIGH = "high"           # CVSS 7.0-8.9
    MEDIUM = "medium"       # CVSS 4.0-6.9
    LOW = "low"             # CVSS 0.1-3.9
    NONE = "none"           # CVSS 0.0 or informational


# -----------------------------------------------------------------------------
# Supporting Models
# -----------------------------------------------------------------------------

class CVEFinding(BaseModel):
    """Individual CVE finding within an assessment."""
    
    cve_id: str = Field(description="CVE identifier (e.g., CVE-2025-55182)")
    severity: SeverityLevel = Field(description="Severity classification")
    cvss_score: Optional[float] = Field(default=None, ge=0.0, le=10.0, description="CVSS score if known")
    status: VulnerabilityStatus = Field(description="Status of this vulnerability in our systems")
    affected_components: List[str] = Field(default_factory=list, description="List of affected components/packages")
    versions_checked: Dict[str, str] = Field(default_factory=dict, description="Component versions audited")
    mitigation_applied: Optional[str] = Field(default=None, description="Mitigation if status is mitigated")
    patch_applied: Optional[str] = Field(default=None, description="Patch version if status is patched")
    notes: Optional[str] = Field(default=None, description="Additional context or findings")
    
    model_config = ConfigDictLike(frozen=True)


class DependencyAuditResult(BaseModel):
    """Result of auditing a specific dependency category."""
    
    category: str = Field(description="Dependency category (e.g., 'react', 'java', 'python')")
    packages_scanned: int = Field(ge=0, description="Number of packages/dependencies scanned")
    vulnerable_found: int = Field(ge=0, description="Number of vulnerable packages found")
    patched: int = Field(ge=0, description="Number patched during this assessment")
    mitigated: int = Field(ge=0, description="Number mitigated but not patched")
    details: List[Dict[str, Any]] = Field(default_factory=list, description="Per-package details")
    
    model_config = ConfigDictLike(frozen=True)


# -----------------------------------------------------------------------------
# Main Receipt
# -----------------------------------------------------------------------------

class SecurityAssessmentReceipt(BaseReceipt):
    """
    Receipt emitted after a security assessment sweep.
    
    Constitutional significance: Security is a dignity concern. An organism
    that can be compromised cannot guarantee dignity preservation. This receipt
    creates auditable proof that security due diligence was performed.
    """
    
    receipt_type: str = "SecurityAssessmentReceipt"
    domain: str = Field(default=Domain.GOVERNANCE.value)
    
    # Assessment metadata
    assessment_id: str = Field(description="Unique identifier for this assessment")
    scope: AssessmentScope = Field(description="Scope of the assessment")
    triggered_by: str = Field(description="What triggered this assessment (e.g., 'scheduled', 'cve_bulletin', 'incident')")
    assessment_ts: datetime = Field(
        default_factory=lambda: datetime.now(timezone.utc),
        description="When the assessment was performed"
    )
    
    # CVE findings
    cve_findings: List[CVEFinding] = Field(default_factory=list, description="Individual CVE findings")
    
    # Dependency audit results
    dependency_audits: List[DependencyAuditResult] = Field(
        default_factory=list, 
        description="Results by dependency category"
    )
    
    # Summary statistics
    total_cves_checked: int = Field(ge=0, description="Total CVEs evaluated")
    critical_found: int = Field(ge=0, default=0, description="Critical severity findings")
    high_found: int = Field(ge=0, default=0, description="High severity findings")
    not_affected_count: int = Field(ge=0, default=0, description="CVEs we're not affected by")
    action_required: bool = Field(default=False, description="Whether immediate action is required")
    
    # Recommendations
    recommendations: List[str] = Field(default_factory=list, description="Recommended actions")
    
    # Constitutional alignment
    constitutional_notes: Optional[str] = Field(
        default=None,
        description="How this assessment relates to constitutional principles"
    )
    
    # Attestation / signing
    assessor: str = Field(default="automated", description="Who/what performed the assessment")
    verified: bool = Field(default=False, description="Whether findings were manually verified")
    
    @model_validator(mode="after")
    def _validate_counts(self) -> "SecurityAssessmentReceipt":
        """Ensure counts are consistent with findings."""
        # Count severities from findings
        critical = sum(1 for f in self.cve_findings if f.severity == SeverityLevel.CRITICAL)
        high = sum(1 for f in self.cve_findings if f.severity == SeverityLevel.HIGH)
        not_affected = sum(1 for f in self.cve_findings if f.status == VulnerabilityStatus.NOT_AFFECTED)
        
        # Update counts if they're defaults
        if self.critical_found == 0 and critical > 0:
            object.__setattr__(self, "critical_found", critical)
        if self.high_found == 0 and high > 0:
            object.__setattr__(self, "high_found", high)
        if self.not_affected_count == 0 and not_affected > 0:
            object.__setattr__(self, "not_affected_count", not_affected)
            
        return self


# -----------------------------------------------------------------------------
# Factory helpers
# -----------------------------------------------------------------------------

def create_cve_sweep_receipt(
    assessment_id: str,
    cve_findings: List[CVEFinding],
    dependency_audits: List[DependencyAuditResult],
    triggered_by: str = "cve_bulletin",
    recommendations: Optional[List[str]] = None,
    constitutional_notes: Optional[str] = None,
) -> SecurityAssessmentReceipt:
    """Create a receipt for a CVE sweep assessment."""
    
    return SecurityAssessmentReceipt(
        assessment_id=assessment_id,
        scope=AssessmentScope.TARGETED,
        triggered_by=triggered_by,
        cve_findings=cve_findings,
        dependency_audits=dependency_audits,
        total_cves_checked=len(cve_findings),
        action_required=any(
            f.status == VulnerabilityStatus.AFFECTED 
            and f.severity in (SeverityLevel.CRITICAL, SeverityLevel.HIGH)
            for f in cve_findings
        ),
        recommendations=recommendations or [],
        constitutional_notes=constitutional_notes,
        assessor="automated",
    )
