from __future__ import annotations

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


class DoctorSeverity(StrEnum):
    """
    诊断结果严重级别。
    """

    Info = "info"
    Warn = "warn"
    Error = "error"


class DoctorFindingStatus(StrEnum):
    """
    单项诊断状态。
    """

    Ok = "ok"
    Skipped = "skipped"
    Degraded = "degraded"
    Failed = "failed"
    Fixed = "fixed"


class DoctorReportStatus(StrEnum):
    """
    整体诊断报告状态。
    """

    Healthy = "healthy"
    Degraded = "degraded"
    Failed = "failed"


@dataclass
class DoctorFinding:
    """
    单条诊断发现，描述问题、原因、建议和可选修复状态。
    """

    id: str
    severity: DoctorSeverity
    status: DoctorFindingStatus
    title: str
    detail: str
    recommendation: str
    fixable: bool = False
    fixed: bool = False
    context: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        """
        转换为稳定的 JSON 字典结构。
        """
        payload: dict[str, Any] = {
            "id": self.id,
            "severity": self.severity.value,
            "status": self.status.value,
            "title": self.title,
            "detail": self.detail,
            "recommendation": self.recommendation,
            "fixable": self.fixable,
            "fixed": self.fixed,
        }
        if self.context:
            payload["context"] = self.context
        return payload


@dataclass
class DoctorReport:
    """
    MoviePilot 离线诊断报告。
    """

    generated_at: datetime
    version: str
    environment: dict[str, Any]
    findings: list[DoctorFinding] = field(default_factory=list)
    schema_version: int = 1

    @property
    def status(self) -> DoctorReportStatus:
        """
        根据诊断发现计算整体状态。
        """
        unresolved = [finding for finding in self.findings if not finding.fixed]
        if any(finding.severity == DoctorSeverity.Error for finding in unresolved):
            return DoctorReportStatus.Failed
        if any(finding.severity == DoctorSeverity.Warn for finding in unresolved):
            return DoctorReportStatus.Degraded
        return DoctorReportStatus.Healthy

    @property
    def summary(self) -> dict[str, int]:
        """
        统计不同严重级别的诊断发现数量。
        """
        counts = {
            "total": len(self.findings),
            "info": 0,
            "warn": 0,
            "error": 0,
            "fixed": 0,
        }
        for finding in self.findings:
            counts[finding.severity.value] += 1
            if finding.fixed:
                counts["fixed"] += 1
        return counts

    def exit_code(self) -> int:
        """
        返回适合 CLI 和自动化脚本使用的退出码。
        """
        return 2 if self.status == DoctorReportStatus.Failed else 0

    def add_finding(self, finding: DoctorFinding) -> None:
        """
        添加一条诊断发现。
        """
        self.findings.append(finding)

    def find(self, finding_id: str) -> Optional[DoctorFinding]:
        """
        按诊断项 ID 查找发现。
        """
        for finding in self.findings:
            if finding.id == finding_id:
                return finding
        return None

    def to_dict(self) -> dict[str, Any]:
        """
        转换为稳定的 JSON 字典结构。
        """
        return {
            "schema_version": self.schema_version,
            "status": self.status.value,
            "generated_at": self.generated_at.isoformat(timespec="seconds"),
            "version": self.version,
            "environment": self.environment,
            "summary": self.summary,
            "findings": [finding.to_dict() for finding in self.findings],
        }
