"""
Data models for security audit results.

Provides structured representations for:
- Individual audit findings with severity, CWE, and OWASP classification
- Audit summary with severity breakdown and scan metrics
- Complete audit result with findings, recommendations, and AI confidence
"""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import StrEnum
from typing import Any


class AuditSeverity(StrEnum):
    """Severity level for a security audit finding."""

    CRITICAL = "critical"
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"
    INFO = "info"


class AuditStatus(StrEnum):
    """Status of a security audit scan."""

    PENDING = "pending"
    ANALYZING = "analyzing"
    COMPLETE = "complete"
    ERROR = "error"


@dataclass
class AuditFinding:
    """A single security audit finding.

    Attributes:
        id: Unique identifier for the finding.
        severity: Severity level (critical, high, medium, low, info).
        category: Category of vulnerability (e.g., authentication, injection).
        title: Short title describing the finding.
        description: Detailed description of the vulnerability.
        affected_file: Path to the affected source file.
        affected_line: Line number in the affected file, if applicable.
        recommendation: Suggested remediation action.
        fix_code: Optional code snippet showing the suggested fix.
        references: List of reference URLs (documentation, CVEs, etc.).
        cwe_id: Common Weakness Enumeration identifier, if applicable.
        owasp_category: OWASP Top 10 category, if applicable.
    """

    id: str
    severity: AuditSeverity
    category: str
    title: str
    description: str
    affected_file: str
    affected_line: int | None
    recommendation: str
    fix_code: str | None
    references: list[str] = field(default_factory=list)
    cwe_id: str | None = None
    owasp_category: str | None = None

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> AuditFinding:
        """Create an AuditFinding from a dictionary (e.g., JSON response).

        Args:
            data: Dictionary containing finding data.

        Returns:
            AuditFinding instance.
        """
        severity_raw = data.get("severity", "info")
        try:
            severity = AuditSeverity(severity_raw.lower())
        except ValueError:
            severity = AuditSeverity.INFO

        return cls(
            id=data.get("id", ""),
            severity=severity,
            category=data.get("category", "unknown"),
            title=data.get("title", ""),
            description=data.get("description", ""),
            affected_file=data.get("affected_file", ""),
            affected_line=data.get("affected_line"),
            recommendation=data.get("recommendation", ""),
            fix_code=data.get("fix_code"),
            references=data.get("references", []),
            cwe_id=data.get("cwe_id"),
            owasp_category=data.get("owasp_category"),
        )

    def to_dict(self) -> dict[str, Any]:
        """Serialize finding to dictionary."""
        return {
            "id": self.id,
            "severity": self.severity.value,
            "category": self.category,
            "title": self.title,
            "description": self.description,
            "affected_file": self.affected_file,
            "affected_line": self.affected_line,
            "recommendation": self.recommendation,
            "fix_code": self.fix_code,
            "references": self.references,
            "cwe_id": self.cwe_id,
            "owasp_category": self.owasp_category,
        }


@dataclass
class AuditSummary:
    """Summary statistics for a security audit.

    Attributes:
        total_findings: Total number of findings across all severities.
        critical_count: Number of critical-severity findings.
        high_count: Number of high-severity findings.
        medium_count: Number of medium-severity findings.
        low_count: Number of low-severity findings.
        info_count: Number of informational findings.
        scan_duration_seconds: Wall-clock time for the scan in seconds.
        files_scanned: Number of source files analyzed.
        lines_scanned: Total lines of code analyzed.
    """

    total_findings: int
    critical_count: int
    high_count: int
    medium_count: int
    low_count: int
    info_count: int
    scan_duration_seconds: float
    files_scanned: int
    lines_scanned: int

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> AuditSummary:
        """Create an AuditSummary from a dictionary.

        Args:
            data: Dictionary containing summary data.

        Returns:
            AuditSummary instance.
        """
        return cls(
            total_findings=data.get("total_findings", 0),
            critical_count=data.get("critical_count", 0),
            high_count=data.get("high_count", 0),
            medium_count=data.get("medium_count", 0),
            low_count=data.get("low_count", 0),
            info_count=data.get("info_count", 0),
            scan_duration_seconds=data.get("scan_duration_seconds", 0.0),
            files_scanned=data.get("files_scanned", 0),
            lines_scanned=data.get("lines_scanned", 0),
        )

    def to_dict(self) -> dict[str, Any]:
        """Serialize summary to dictionary."""
        return {
            "total_findings": self.total_findings,
            "critical_count": self.critical_count,
            "high_count": self.high_count,
            "medium_count": self.medium_count,
            "low_count": self.low_count,
            "info_count": self.info_count,
            "scan_duration_seconds": self.scan_duration_seconds,
            "files_scanned": self.files_scanned,
            "lines_scanned": self.lines_scanned,
        }


@dataclass
class SecurityAuditResult:
    """Complete result of a security audit scan.

    Attributes:
        audit_id: Unique identifier for this audit run.
        status: Current status of the audit scan.
        summary: Summary statistics, available when status is COMPLETE.
        findings: List of individual findings discovered.
        recommendations: High-level security recommendations.
        scan_scope: Scope of the scan (full, targeted, quick).
        timestamp: ISO 8601 timestamp of when the audit was initiated.
        ai_confidence: AI model confidence in its analysis (0.0 to 1.0).
    """

    audit_id: str
    status: AuditStatus
    summary: AuditSummary | None
    findings: list[AuditFinding]
    recommendations: list[str]
    scan_scope: str
    timestamp: str
    ai_confidence: float

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> SecurityAuditResult:
        """Create a SecurityAuditResult from a dictionary.

        Args:
            data: Dictionary containing full audit result data.

        Returns:
            SecurityAuditResult instance.
        """
        status_raw = data.get("status", "pending")
        try:
            status = AuditStatus(status_raw.lower())
        except ValueError:
            status = AuditStatus.PENDING

        summary_data = data.get("summary")
        summary = AuditSummary.from_dict(summary_data) if summary_data else None

        findings_data = data.get("findings", [])
        findings = [AuditFinding.from_dict(f) for f in findings_data]

        return cls(
            audit_id=data.get("audit_id", ""),
            status=status,
            summary=summary,
            findings=findings,
            recommendations=data.get("recommendations", []),
            scan_scope=data.get("scan_scope", "full"),
            timestamp=data.get("timestamp", ""),
            ai_confidence=float(data.get("ai_confidence", 0.0)),
        )

    def to_dict(self) -> dict[str, Any]:
        """Serialize full audit result to dictionary."""
        return {
            "audit_id": self.audit_id,
            "status": self.status.value,
            "summary": self.summary.to_dict() if self.summary else None,
            "findings": [f.to_dict() for f in self.findings],
            "recommendations": self.recommendations,
            "scan_scope": self.scan_scope,
            "timestamp": self.timestamp,
            "ai_confidence": self.ai_confidence,
        }
