from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional


@dataclass
class Evidence:
    file: str
    line: int
    code_snippet: str
    pattern_name: str

    def to_dict(self) -> Dict[str, Any]:
        return {
            "file": self.file,
            "line": self.line,
            "code_snippet": self.code_snippet,
            "pattern_name": self.pattern_name,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> Evidence:
        return cls(
            file=data["file"],
            line=data["line"],
            code_snippet=data["code_snippet"],
            pattern_name=data["pattern_name"],
        )


@dataclass
class Capability:
    category: str  # system_execution | network_access | secret_access | dynamic_code | obfuscation | file_system_access
    description: str
    evidence: List[Evidence] = field(default_factory=list)
    severity: str = "Low"  # Low | Medium | High | Critical

    def to_dict(self) -> Dict[str, Any]:
        return {
            "category": self.category,
            "description": self.description,
            "evidence": [e.to_dict() for e in self.evidence],
            "severity": self.severity,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> Capability:
        return cls(
            category=data["category"],
            description=data["description"],
            evidence=[Evidence.from_dict(e) for e in data.get("evidence", [])],
            severity=data.get("severity", "Low"),
        )


@dataclass
class PluginUnit:
    id: str
    name: str
    path: str
    type: str  # folder | file
    language: str  # python | javascript | typescript
    hash: str

    def to_dict(self) -> Dict[str, Any]:
        return {
            "id": self.id,
            "name": self.name,
            "path": self.path,
            "type": self.type,
            "language": self.language,
            "hash": self.hash,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> PluginUnit:
        return cls(
            id=data["id"],
            name=data["name"],
            path=data["path"],
            type=data["type"],
            language=data["language"],
            hash=data["hash"],
        )


@dataclass
class ScanResult:
    plugin_id: str
    capabilities: List[Capability] = field(default_factory=list)
    risk_level: str = "Low"
    timestamp: str = ""
    dependencies: List[str] = field(default_factory=list)
    skills: List[str] = field(default_factory=list)
    description: str = ""
    file_count: int = 0
    total_lines: int = 0

    def to_dict(self) -> Dict[str, Any]:
        return {
            "plugin_id": self.plugin_id,
            "capabilities": [c.to_dict() for c in self.capabilities],
            "risk_level": self.risk_level,
            "timestamp": self.timestamp,
            "dependencies": self.dependencies,
            "skills": self.skills,
            "description": self.description,
            "file_count": self.file_count,
            "total_lines": self.total_lines,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> ScanResult:
        return cls(
            plugin_id=data["plugin_id"],
            capabilities=[Capability.from_dict(c) for c in data.get("capabilities", [])],
            risk_level=data.get("risk_level", "Low"),
            timestamp=data.get("timestamp", ""),
            dependencies=data.get("dependencies", []),
            skills=data.get("skills", []),
            description=data.get("description", ""),
            file_count=data.get("file_count", 0),
            total_lines=data.get("total_lines", 0),
        )


@dataclass
class DriftEvent:
    plugin_id: str
    event_type: str  # new | modified | removed
    capability_changes: List[Dict[str, Any]] = field(default_factory=list)
    severity: str = "Medium"

    def to_dict(self) -> Dict[str, Any]:
        return {
            "plugin_id": self.plugin_id,
            "event_type": self.event_type,
            "capability_changes": self.capability_changes,
            "severity": self.severity,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> DriftEvent:
        return cls(
            plugin_id=data["plugin_id"],
            event_type=data["event_type"],
            capability_changes=data.get("capability_changes", []),
            severity=data.get("severity", "Medium"),
        )


@dataclass
class SecurityState:
    project_id: str
    scan_id: str
    timestamp: str
    total_plugins: int
    risk_summary: Dict[str, int] = field(default_factory=dict)
    top_findings: List[Dict[str, Any]] = field(default_factory=list)

    def to_dict(self) -> Dict[str, Any]:
        return {
            "project_id": self.project_id,
            "scan_id": self.scan_id,
            "timestamp": self.timestamp,
            "total_plugins": self.total_plugins,
            "risk_summary": self.risk_summary,
            "top_findings": self.top_findings,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> SecurityState:
        return cls(
            project_id=data["project_id"],
            scan_id=data["scan_id"],
            timestamp=data["timestamp"],
            total_plugins=data["total_plugins"],
            risk_summary=data.get("risk_summary", {}),
            top_findings=data.get("top_findings", []),
        )


@dataclass
class CapabilitySurface:
    project_id: str
    plugins: List[Dict[str, Any]] = field(default_factory=list)

    def to_dict(self) -> Dict[str, Any]:
        return {
            "project_id": self.project_id,
            "plugins": self.plugins,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> CapabilitySurface:
        return cls(
            project_id=data["project_id"],
            plugins=data.get("plugins", []),
        )


@dataclass
class AIBOM:
    version: str
    project_id: str
    timestamp: str
    components: List[Dict[str, Any]] = field(default_factory=list)

    def to_dict(self) -> Dict[str, Any]:
        return {
            "version": self.version,
            "project_id": self.project_id,
            "timestamp": self.timestamp,
            "components": self.components,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> AIBOM:
        return cls(
            version=data["version"],
            project_id=data["project_id"],
            timestamp=data["timestamp"],
            components=data.get("components", []),
        )
