"""IIHS rating engine.

IIHS rates individual body regions as Good/Acceptable/Marginal/Poor.
The overall rating is determined by the worst sub-rating.
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

from impakt.criteria.base import CriterionResult
from impakt.protocol.base import BodyRegionScore, ProtocolResult, Rating

_THRESHOLDS_DIR = Path(__file__).parent / "thresholds"


def _load_iihs_yaml(version: str) -> dict[str, tuple[float, float, float, bool]]:
    """Load IIHS thresholds from YAML."""
    yaml_path = _THRESHOLDS_DIR / f"iihs_{version}.yaml"
    if not yaml_path.exists():
        return {}
    import yaml

    data = yaml.safe_load(yaml_path.read_text(encoding="utf-8"))
    if not isinstance(data, dict):
        return {}
    result: dict[str, tuple[float, float, float, bool]] = {}
    for name, vals in data.items():
        if isinstance(vals, dict):
            result[name] = (
                float(vals["good"]),
                float(vals["acceptable"]),
                float(vals["marginal"]),
                bool(vals.get("higher_is_worse", True)),
            )
    return result


# Hardcoded fallback
_IIHS_2024_FALLBACK: dict[str, tuple[float, float, float, bool]] = {
    "HIC15": (250.0, 500.0, 700.0, True),
    "Chest Deflection": (38.0, 50.0, 63.0, True),
    "Femur Load Left": (3.8, 6.2, 10.0, True),
    "Femur Load Right": (3.8, 6.2, 10.0, True),
    "Nij": (0.52, 0.78, 1.0, True),
    "Tibia Index": (0.5, 0.8, 1.3, True),
}


def _get_iihs_thresholds(version: str) -> dict[str, tuple[float, float, float, bool]]:
    thresholds = _load_iihs_yaml(version)
    if thresholds:
        return thresholds
    if version == "2024":
        return _IIHS_2024_FALLBACK
    return {}


def _rate_value(
    value: float,
    good_limit: float,
    acceptable_limit: float,
    marginal_limit: float,
    higher_is_worse: bool,
) -> Rating:
    """Rate a single value against IIHS thresholds."""
    if higher_is_worse:
        if value <= good_limit:
            return Rating.GOOD
        elif value <= acceptable_limit:
            return Rating.ACCEPTABLE
        elif value <= marginal_limit:
            return Rating.MARGINAL
        else:
            return Rating.POOR
    else:
        if value >= good_limit:
            return Rating.GOOD
        elif value >= acceptable_limit:
            return Rating.ACCEPTABLE
        elif value >= marginal_limit:
            return Rating.MARGINAL
        else:
            return Rating.POOR


RATING_ORDER = {
    Rating.GOOD: 0,
    Rating.ACCEPTABLE: 1,
    Rating.MARGINAL: 2,
    Rating.POOR: 3,
}


class IIHS:
    """IIHS evaluator."""

    def __init__(self, version: str = "2024") -> None:
        self._version = version
        self._thresholds = _get_iihs_thresholds(version)
        if not self._thresholds:
            raise ValueError(
                f"No thresholds found for IIHS version: {version}. "
                f"Check {_THRESHOLDS_DIR} for YAML files."
            )

    @property
    def protocol_name(self) -> str:
        return "IIHS"

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

    def evaluate(
        self,
        criteria: dict[str, CriterionResult],
    ) -> ProtocolResult:
        """Rate criteria against IIHS thresholds."""
        region_scores: list[BodyRegionScore] = []
        worst_rating = Rating.GOOD

        for criterion_name, (
            good,
            acceptable,
            marginal,
            higher_is_worse,
        ) in self._thresholds.items():
            result = criteria.get(criterion_name)
            if result is None:
                for key, res in criteria.items():
                    if (
                        criterion_name.lower() in key.lower()
                        or key.lower() in criterion_name.lower()
                    ):
                        result = res
                        break

            if result is None:
                continue

            rating = _rate_value(
                result.value,
                good,
                acceptable,
                marginal,
                higher_is_worse,
            )

            if RATING_ORDER[rating] > RATING_ORDER[worst_rating]:
                worst_rating = rating

            region_scores.append(
                BodyRegionScore(
                    region=result.body_region or criterion_name,
                    criterion=criterion_name,
                    value=result.value,
                    unit=result.unit,
                    rating=rating,
                )
            )

        return ProtocolResult(
            protocol=self.protocol_name,
            version=self._version,
            overall_rating=worst_rating.value.upper(),
            region_scores=region_scores,
            details={
                "worst_region": worst_rating.value,
            },
        )


def evaluate(
    criteria: dict[str, CriterionResult],
    version: str = "2024",
) -> ProtocolResult:
    """Convenience function for IIHS evaluation."""
    return IIHS(version=version).evaluate(criteria)
