from __future__ import annotations

import enum
from dataclasses import dataclass, field
from pathlib import Path
from typing import Dict, List, Optional, Sequence


class Severity(str, enum.Enum):
    CRITICAL = "critical"
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"
    INFO = "info"
    NOTE = "note"


@dataclass
class FindingDetail:
    category: str
    message: str
    severity: Severity
    file: Optional[str] = None
    line: Optional[int] = None
    evidence: Optional[str] = None
    remediation: Optional[str] = None
    request_example: Optional[str] = None
    requires_auth: Optional[str] = None
    attack_surface: Optional[str] = None


@dataclass
class PluginMetadata:
    name: str = ""
    version: str = ""
    description: str = ""
    author: str = ""
    plugin_uri: str = ""
    author_uri: str = ""
    text_domain: str = ""
    domain_path: str = ""
    requires_at_least: str = ""
    requires_php: str = ""


@dataclass
class Stats:
    total_files: int = 0
    code_bytes: int = 0
    file_types: Dict[str, int] = field(default_factory=dict)
    loc_php: int = 0
    loc_js: int = 0
    loc_css: int = 0


@dataclass
class AttackSurfaceEntry:
    hook_type: str
    hook: str
    callback: str
    priority: Optional[int] = None
    args: Optional[int] = None
    file: Optional[str] = None
    line: Optional[int] = None
    auth_required: Optional[str] = None


@dataclass
class PluginReport:
    plugin_path: str
    resolved_path: str
    metadata: PluginMetadata
    wp_version: str
    php_version: str
    stats: Stats
    findings: List[FindingDetail] = field(default_factory=list)
    attack_surface: List[AttackSurfaceEntry] = field(default_factory=list)
    warnings: List[str] = field(default_factory=list)
    score: int = 100
    grade: str = "N/A"

    def add_finding(self, finding: FindingDetail) -> None:
        self.findings.append(finding)
        self._update_score()

    def _update_score(self) -> None:
        severity_weights = {
            Severity.CRITICAL: 40,
            Severity.HIGH: 25,
            Severity.MEDIUM: 10,
            Severity.LOW: 5,
            Severity.INFO: 0,
            Severity.NOTE: 0,
        }
        penalty = sum(severity_weights.get(f.severity, 0) for f in self.findings)
        self.score = max(0, 100 - penalty)
        self.grade = self._grade_from_score(self.score)

    @staticmethod
    def _grade_from_score(score: int) -> str:
        if score >= 95:
            return "A+"
        if score >= 85:
            return "A"
        if score >= 75:
            return "B"
        if score >= 65:
            return "C"
        if score >= 50:
            return "D"
        return "F"


@dataclass
class ProjectReport:
    target: str
    plugin_reports: List[PluginReport] = field(default_factory=list)
    summary: Dict[str, int] = field(default_factory=dict)

    def compute_summary(self) -> Dict[str, int]:
        summary: Dict[str, int] = {
            "plugins": len(self.plugin_reports),
            "findings": sum(len(p.findings) for p in self.plugin_reports),
        }
        by_severity: Dict[str, int] = {}
        by_grade: Dict[str, int] = {}
        for p in self.plugin_reports:
            by_grade[p.grade] = by_grade.get(p.grade, 0) + 1
            for f in p.findings:
                by_severity[f.severity.value] = by_severity.get(f.severity.value, 0) + 1
        summary.update({f"severity_{k}": v for k, v in by_severity.items()})
        summary.update({f"grade_{k}": v for k, v in by_grade.items()})
        self.summary = summary
        return summary


def plugin_name_from_path(path: Path) -> str:
    return path.name.rstrip("/").split("/")[-1]
