"""Base types for rating protocol scorers."""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Protocol, runtime_checkable

from impakt.criteria.base import CriterionResult


class Rating(Enum):
    """Universal rating levels."""

    GOOD = "good"
    ACCEPTABLE = "acceptable"
    MARGINAL = "marginal"
    POOR = "poor"


class Color(Enum):
    """Euro NCAP body region color codes."""

    GREEN = "green"
    YELLOW = "yellow"
    ORANGE = "orange"
    BROWN = "brown"
    RED = "red"


@dataclass(frozen=True)
class BodyRegionScore:
    """Score for a single body region within a protocol evaluation."""

    region: str
    criterion: str
    value: float
    unit: str = ""
    rating: Rating | None = None
    color: Color | None = None
    points: float = 0.0
    max_points: float = 0.0
    details: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class ProtocolResult:
    """Complete result of a protocol evaluation.

    Contains the overall rating/score plus per-region breakdowns.
    """

    protocol: str
    version: str
    overall_rating: str = ""
    stars: int | None = None
    total_points: float = 0.0
    max_points: float = 0.0
    percentage: float = 0.0
    region_scores: list[BodyRegionScore] = field(default_factory=list)
    details: dict[str, Any] = field(default_factory=dict)

    def to_pdf(self, path: str) -> None:
        """Generate a protocol report PDF."""
        from impakt.report.engine import generate_protocol_report

        generate_protocol_report(self, path)

    def summary(self) -> str:
        """Human-readable summary of the result."""
        lines = [f"{self.protocol} {self.version}"]
        if self.stars is not None:
            lines.append(f"  Rating: {'*' * self.stars} ({self.stars}/5 stars)")
        if self.overall_rating:
            lines.append(f"  Overall: {self.overall_rating}")
        if self.max_points > 0:
            lines.append(
                f"  Score: {self.total_points:.1f}/{self.max_points:.1f} ({self.percentage:.0f}%)"
            )
        lines.append("")
        for rs in self.region_scores:
            rating_str = ""
            if rs.color is not None:
                rating_str = f" [{rs.color.value}]"
            elif rs.rating is not None:
                rating_str = f" [{rs.rating.value}]"
            points_str = f" ({rs.points:.1f}/{rs.max_points:.1f})" if rs.max_points > 0 else ""
            lines.append(f"  {rs.region}: {rs.value:.2f} {rs.unit}{rating_str}{points_str}")
        return "\n".join(lines)

    def __repr__(self) -> str:
        if self.stars is not None:
            return f"ProtocolResult({self.protocol} {self.version}: {self.stars} stars)"
        return f"ProtocolResult({self.protocol} {self.version}: {self.overall_rating})"


@runtime_checkable
class ProtocolScorer(Protocol):
    """Protocol for rating protocol scorers."""

    @property
    def protocol_name(self) -> str: ...

    @property
    def version(self) -> str: ...

    def evaluate(
        self,
        criteria: dict[str, CriterionResult],
    ) -> ProtocolResult:
        """Evaluate criteria results against this protocol."""
        ...
