from __future__ import annotations
from dataclasses import dataclass, field, asdict
from typing import Any

SEVERITIES = ("good", "normal", "notgood", "bad", "serious", "info")
SEVERITY_LABELS = {
    "good": "Good",
    "normal": "Normal",
    "notgood": "Not Good",
    "bad": "Bad",
    "serious": "Serious",
    "info": "Info",
}
SEVERITY_COLORS = {
    "good": "bright-green",
    "normal": "bright-blue",
    "notgood": "bright-yellow",
    "bad": "bright-red",
    "serious": "bright-purple",
    "info": "tx-alt",
}

# 4 main groups for the results UI tabs.
GROUPS = ("reliability", "safety", "vulnerabilities", "compatibility")
GROUP_LABELS = {
    "reliability": "信頼性",
    "safety": "安全性",
    "vulnerabilities": "脆弱性",
    "compatibility": "互換性",
}


@dataclass
class Finding:
    # 'group' is the coarse tab (reliability/safety/vulnerabilities/compatibility).
    # 'category' is the fine-grained sub-category label shown as a chip on each finding.
    # 'step' is the machine-friendly phase slug that produced this finding
    # (e.g. "protocols", "ciphers", "handshake_sim"). Shown in the log as "[step]".
    category: str
    title: str
    detail: str = ""
    severity: str = "info"
    weight: int = 0
    group: str = ""
    step: str = ""

    def to_dict(self) -> dict[str, Any]:
        d = asdict(self)
        d["severity_label"] = SEVERITY_LABELS.get(self.severity, self.severity)
        d["color"] = SEVERITY_COLORS.get(self.severity, "tx")
        # impact is what the UI sorts by for the Summary tab.
        mul = {"good": 0.0, "normal": 0.0, "notgood": 1.0, "bad": 3.0, "serious": 9.0, "info": 0.0}.get(self.severity, 0.0)
        d["impact"] = mul * float(self.weight)
        return d


@dataclass
class ScanResult:
    target: str
    host: str
    port: int
    started_at: float
    finished_at: float = 0.0
    findings: list[Finding] = field(default_factory=list)
    data: dict[str, Any] = field(default_factory=dict)
    rank: str = ""
    score: float = 0.0
    error: str | None = None

    def add(self, f: Finding) -> None:
        self.findings.append(f)

    def to_dict(self) -> dict[str, Any]:
        return {
            "target": self.target,
            "host": self.host,
            "port": self.port,
            "started_at": self.started_at,
            "finished_at": self.finished_at,
            "duration": max(0.0, self.finished_at - self.started_at),
            "findings": [f.to_dict() for f in self.findings],
            "data": self.data,
            "rank": self.rank,
            "score": self.score,
            "error": self.error,
        }


@dataclass
class ProgressMessage:
    phase: str
    detail: str
    progress: float
    severity: str = "info"
    finding: dict[str, Any] | None = None

    def to_dict(self) -> dict[str, Any]:
        return {
            "phase": self.phase,
            "detail": self.detail,
            "progress": self.progress,
            "severity": self.severity,
            "finding": self.finding,
        }
