"""
Cooling performance analysis for Sentinel Brain.
"""

from dataclasses import dataclass, field
from statistics import mean, pstdev

from sentinel.brain.findings import Finding


@dataclass
class CoolingHealthResult:
    """
    Result of the cooling performance analysis.

    Attributes:
        score: Cooling subsystem score from 0 to 100.
        findings: Explainable cooling findings.
    """

    score: float
    findings: list[Finding] = field(default_factory=list)


class CoolingHealthAnalyzer:
    """
    Evaluate cooling performance from equipment history.
    """

    MINIMUM_SAMPLE_COUNT = 30
    BASELINE_RATIO = 0.75

    @staticmethod
    def _valid_rows(
        history: list[dict[str, object]],
    ) -> list[dict[str, float]]:
        """
        Return rows containing all required cooling values.
        """
        valid_rows: list[dict[str, float]] = []

        for row in history:
            try:
                valid_rows.append(
                    {
                        "internal": float(
                            row["internal_temperature_c"]
                        ),
                        "evaporator": float(
                            row["evaporator_temperature_c"]
                        ),
                        "compressor": float(
                            row["compressor_temperature_c"]
                        ),
                        "current": float(
                            row["compressor_current_a"]
                        ),
                    }
                )
            except (KeyError, TypeError, ValueError):
                continue

        return valid_rows

    @classmethod
    def _split_history(
        cls,
        rows: list[dict[str, float]],
    ) -> tuple[
        list[dict[str, float]],
        list[dict[str, float]],
    ]:
        """
        Split measurements into baseline and current windows.
        """
        split_index = int(
            len(rows) * cls.BASELINE_RATIO
        )

        split_index = max(
            cls.MINIMUM_SAMPLE_COUNT,
            split_index,
        )

        split_index = min(
            split_index,
            len(rows) - 1,
        )

        return (
            rows[:split_index],
            rows[split_index:],
        )

    @staticmethod
    def _evaporator_delta(
        row: dict[str, float],
    ) -> float:
        """
        Return internal-to-evaporator temperature difference.
        """
        return row["internal"] - row["evaporator"]

    @classmethod
    def _delta_values(
        cls,
        rows: list[dict[str, float]],
    ) -> list[float]:
        """
        Return evaporator delta values.
        """
        return [
            cls._evaporator_delta(row)
            for row in rows
        ]

    @classmethod
    def analyze(
        cls,
        history: list[dict[str, object]],
    ) -> CoolingHealthResult:
        """
        Analyze historical cooling performance.

        Args:
            history: Measurements ordered from oldest to newest.

        Returns:
            Cooling score and explainable findings.
        """
        rows = cls._valid_rows(history)

        if len(rows) < cls.MINIMUM_SAMPLE_COUNT:
            return CoolingHealthResult(
                score=0.0,
                findings=[
                    Finding(
                        code="COOLING_DATA_INSUFFICIENT",
                        severity="LOW",
                        confidence=100.0,
                        explanation=(
                            "Insufficient historical data "
                            "to evaluate cooling performance."
                        ),
                        metric="cooling_sample_count",
                        value=float(len(rows)),
                        unit="samples",
                    )
                ],
            )

        baseline_rows, current_rows = cls._split_history(rows)

        baseline_deltas = cls._delta_values(baseline_rows)
        current_deltas = cls._delta_values(current_rows)

        baseline_delta_mean = mean(baseline_deltas)
        current_delta_mean = mean(current_deltas)

        baseline_delta_std = (
            pstdev(baseline_deltas)
            if len(baseline_deltas) >= 2
            else 0.0
        )

        current_delta_std = (
            pstdev(current_deltas)
            if len(current_deltas) >= 2
            else 0.0
        )

        delta_deviation = current_delta_mean - baseline_delta_mean

        current_compressor_mean = mean(
            row["compressor"] for row in current_rows
        )
        baseline_compressor_mean = mean(
            row["compressor"] for row in baseline_rows
        )
        compressor_deviation = (
            current_compressor_mean - baseline_compressor_mean
        )

        current_current_mean = mean(
            row["current"] for row in current_rows
        )
        baseline_current_mean = mean(
            row["current"] for row in baseline_rows
        )
        electrical_deviation = (
            current_current_mean - baseline_current_mean
        )

        findings: list[Finding] = []
        penalty = 0.0

        if abs(delta_deviation) >= 3.0:
            penalty += 30.0
            findings.append(
                Finding(
                    code="EVAPORATOR_DELTA_DEVIATION",
                    severity="HIGH",
                    confidence=92.0,
                    explanation=(
                        "The internal-to-evaporator temperature "
                        "difference has changed significantly. "
                        f"Current average: {current_delta_mean:.2f} °C; "
                        f"baseline: {baseline_delta_mean:.2f} °C."
                    ),
                    metric="evaporator_delta_deviation",
                    value=round(delta_deviation, 4),
                    unit="°C",
                )
            )
        elif abs(delta_deviation) >= 1.5:
            penalty += 12.0
            findings.append(
                Finding(
                    code="EVAPORATOR_DELTA_DRIFT",
                    severity="MEDIUM",
                    confidence=85.0,
                    explanation=(
                        "A gradual change in evaporator performance "
                        "has been detected. "
                        f"Current average delta: {current_delta_mean:.2f} °C; "
                        f"baseline: {baseline_delta_mean:.2f} °C."
                    ),
                    metric="evaporator_delta_deviation",
                    value=round(delta_deviation, 4),
                    unit="°C",
                )
            )
        else:
            findings.append(
                Finding(
                    code="EVAPORATOR_DELTA_BASELINE_OK",
                    severity="INFO",
                    confidence=95.0,
                    explanation=(
                        "The internal-to-evaporator temperature "
                        "difference remains consistent with this "
                        "equipment's baseline."
                    ),
                    metric="evaporator_delta_deviation",
                    value=round(delta_deviation, 4),
                    unit="°C",
                )
            )

        if current_delta_std > max(2.0, baseline_delta_std * 2.5):
            penalty += 20.0
            findings.append(
                Finding(
                    code="EVAPORATOR_DELTA_UNSTABLE",
                    severity="HIGH",
                    confidence=88.0,
                    explanation=(
                        "Cooling temperature difference has become "
                        "unusually unstable. "
                        f"Current variability: {current_delta_std:.2f} °C; "
                        f"baseline variability: {baseline_delta_std:.2f} °C."
                    ),
                    metric="evaporator_delta_stability",
                    value=round(current_delta_std, 4),
                    unit="°C",
                )
            )
        else:
            findings.append(
                Finding(
                    code="EVAPORATOR_DELTA_STABLE",
                    severity="INFO",
                    confidence=92.0,
                    explanation=(
                        "Cooling temperature difference remains stable."
                    ),
                    metric="evaporator_delta_stability",
                    value=round(current_delta_std, 4),
                    unit="°C",
                )
            )

        if (
            compressor_deviation >= 5.0
            and electrical_deviation >= 0.20
        ):
            penalty += 25.0
            findings.append(
                Finding(
                    code="COOLING_EFFORT_INCREASED",
                    severity="HIGH",
                    confidence=90.0,
                    explanation=(
                        "The compressor is operating hotter and drawing "
                        "more current than its equipment baseline while "
                        "maintaining the same cooling function."
                    ),
                    metric="cooling_effort_index",
                    value=round(
                        compressor_deviation + electrical_deviation,
                        4,
                    ),
                    unit="index",
                )
            )
        elif (
            compressor_deviation >= 2.5
            or electrical_deviation >= 0.10
        ):
            penalty += 10.0
            findings.append(
                Finding(
                    code="COOLING_EFFORT_DRIFT",
                    severity="MEDIUM",
                    confidence=82.0,
                    explanation=(
                        "A moderate increase in compressor effort has "
                        "been detected relative to this equipment's baseline."
                    ),
                    metric="cooling_effort_index",
                    value=round(
                        compressor_deviation + electrical_deviation,
                        4,
                    ),
                    unit="index",
                )
            )
        else:
            findings.append(
                Finding(
                    code="COOLING_EFFORT_BASELINE_OK",
                    severity="INFO",
                    confidence=92.0,
                    explanation=(
                        "Compressor thermal and electrical effort remain "
                        "consistent with the equipment baseline."
                    ),
                    metric="cooling_effort_index",
                    value=round(
                        compressor_deviation + electrical_deviation,
                        4,
                    ),
                    unit="index",
                )
            )

        score = round(
            max(
                0.0,
                min(100.0, 100.0 - penalty),
            ),
            2,
        )

        return CoolingHealthResult(
            score=score,
            findings=findings,
        )
