"""
Sentinel Brain orchestration engine.
"""

from datetime import datetime

from sentinel.brain.analysis import AnalysisResult
from sentinel.brain.baseline import (
    BaselineComparison,
    EquipmentBaseline,
)
from sentinel.brain.cooling_health import CoolingHealthAnalyzer
from sentinel.brain.findings import Finding
from sentinel.brain.health_score import HealthScore
from sentinel.brain.indicators import Indicators
from sentinel.brain.prediction import PredictionEngine
from sentinel.brain.root_cause import RootCauseAnalyzer
from sentinel.brain.rules import Rules
from sentinel.brain.sensor_health import SensorHealthAnalyzer
from sentinel.brain.trends import TrendIndicators


class SentinelBrain:
    """
    Analyze equipment measurements and historical behavior.
    """

    def analyze(
        self,
        measurement: dict[str, object],
    ) -> AnalysisResult:
        """
        Analyze one measurement.

        This method preserves Sentinel Brain V1 compatibility.
        """
        compressor_stress = Indicators.compressor_stress(
            compressor_temperature=float(
                measurement["compressor_temperature_c"]
            ),
            compressor_current=float(
                measurement["compressor_current_a"]
            ),
        )

        health_score = HealthScore.compute(
            compressor_stress=compressor_stress,
        )

        status = Rules.status(health_score)

        if status == "EXCELLENT":
            analysis = "No anomaly detected."
            recommendation = "No action required."

        elif status == "SURVEILLANCE":
            analysis = (
                "A minor compressor stress indicator "
                "requires continued monitoring."
            )
            recommendation = (
                "Monitor the next operating cycles."
            )

        elif status == "ATTENTION":
            analysis = (
                "Elevated compressor stress has been detected."
            )
            recommendation = (
                "Inspect compressor temperature "
                "and electrical load."
            )

        else:
            analysis = (
                "Critical compressor stress has been detected."
            )
            recommendation = (
                "Technical inspection is recommended immediately."
            )

        return AnalysisResult(
            health_score=health_score,
            status=status,
            analysis=analysis,
            recommendation=recommendation,
            confidence=100.0,
            prediction_horizon_days=None,
            thermal_score=None,
            electrical_score=None,
            cooling_score=None,
            sensor_score=None,
            root_cause_code=None,
            root_cause=None,
            root_cause_confidence=None,
            root_cause_explanation=None,
            findings=[],
        )

    @staticmethod
    def _baseline_finding(
        comparison: BaselineComparison,
        stable_code: str,
        warning_code: str,
        critical_code: str,
        label: str,
        unit: str,
    ) -> tuple[Finding, float]:
        """
        Convert one baseline comparison into a Finding and penalty.
        """
        absolute_z_score = abs(comparison.z_score)

        if absolute_z_score >= 4.0:
            return (
                Finding(
                    code=critical_code,
                    severity="HIGH",
                    confidence=95.0,
                    explanation=(
                        f"{label} differs significantly from its "
                        f"equipment baseline. Current average: "
                        f"{comparison.current_mean:.3f} {unit}; "
                        f"baseline: "
                        f"{comparison.baseline_mean:.3f} {unit}; "
                        f"deviation: "
                        f"{comparison.absolute_deviation:+.3f} {unit}."
                    ),
                    metric=comparison.metric,
                    value=comparison.absolute_deviation,
                    unit=unit,
                ),
                25.0,
            )

        if absolute_z_score >= 2.5:
            return (
                Finding(
                    code=warning_code,
                    severity="MEDIUM",
                    confidence=88.0,
                    explanation=(
                        f"{label} is drifting from its equipment "
                        f"baseline. Current average: "
                        f"{comparison.current_mean:.3f} {unit}; "
                        f"baseline: "
                        f"{comparison.baseline_mean:.3f} {unit}; "
                        f"deviation: "
                        f"{comparison.absolute_deviation:+.3f} {unit}."
                    ),
                    metric=comparison.metric,
                    value=comparison.absolute_deviation,
                    unit=unit,
                ),
                10.0,
            )

        return (
            Finding(
                code=stable_code,
                severity="INFO",
                confidence=95.0,
                explanation=(
                    f"{label} remains consistent with this "
                    f"equipment's baseline. Current average: "
                    f"{comparison.current_mean:.3f} {unit}; "
                    f"baseline: "
                    f"{comparison.baseline_mean:.3f} {unit}."
                ),
                metric=comparison.metric,
                value=comparison.absolute_deviation,
                unit=unit,
            ),
            0.0,
        )

    def analyze_history(
        self,
        history: list[dict[str, object]],
    ) -> AnalysisResult:
        """
        Analyze equipment trends, baseline deviations, cooling
        performance and sensor health.
        """
        if not history:
            raise ValueError(
                "Measurement history cannot be empty."
            )

        if len(history) < 30:
            result = self.analyze(history[-1])

            result.confidence = 40.0
            result.analysis = (
                "Insufficient historical data for "
                "trend and baseline analysis."
            )
            result.recommendation = (
                "Continue data acquisition."
            )

            return result

        findings: list[Finding] = []

        thermal_penalty = 0.0
        electrical_penalty = 0.0

        internal_drift = (
            TrendIndicators.internal_temperature_drift(
                history
            )
        )

        internal_stability = (
            TrendIndicators.internal_temperature_stability(
                history
            )
        )

        trend_duration_hours = 0.0
        trend_rows = [row for row in history if row.get("recorded_at") and row.get("internal_temperature_c") is not None]
        if len(trend_rows) >= 2:
            try:
                first_ts = datetime.fromisoformat(str(trend_rows[0]["recorded_at"]).replace("Z", "+00:00"))
                last_ts = datetime.fromisoformat(str(trend_rows[-1]["recorded_at"]).replace("Z", "+00:00"))
                trend_duration_hours = max(0.0, (last_ts - first_ts).total_seconds() / 3600.0)
            except ValueError:
                trend_duration_hours = 0.0

        compressor_trend = (
            TrendIndicators.compressor_temperature_trend(
                history
            )
        )

        current_trend = (
            TrendIndicators.compressor_current_trend(
                history
            )
        )

        if internal_drift > 0.50:
            thermal_penalty += 25.0

            findings.append(
                Finding(
                    code="INTERNAL_TEMP_RISING_FAST",
                    severity="HIGH",
                    confidence=90.0,
                    explanation=(
                        "Internal temperature is rising "
                        f"by {internal_drift:.2f} °C per hour over the last {trend_duration_hours:.1f} h of available data."
                    ),
                    metric="internal_temperature_drift",
                    value=internal_drift,
                    unit="°C/h",
                )
            )

        elif internal_drift > 0.15:
            thermal_penalty += 10.0

            findings.append(
                Finding(
                    code="INTERNAL_TEMP_RISING",
                    severity="MEDIUM",
                    confidence=80.0,
                    explanation=(
                        "A gradual internal temperature rise "
                        f"of {internal_drift:.2f} °C per hour has been detected "
                        f"over the last {trend_duration_hours:.1f} h of available data."
                    ),
                    metric="internal_temperature_drift",
                    value=internal_drift,
                    unit="°C/h",
                )
            )

        else:
            findings.append(
                Finding(
                    code="INTERNAL_TEMP_STABLE",
                    severity="INFO",
                    confidence=95.0,
                    explanation=(
                        "Internal temperature trend is stable."
                    ),
                    metric="internal_temperature_drift",
                    value=internal_drift,
                    unit="°C/h",
                )
            )

        if internal_stability > 1.00:
            thermal_penalty += 20.0

            findings.append(
                Finding(
                    code="INTERNAL_TEMP_UNSTABLE",
                    severity="HIGH",
                    confidence=90.0,
                    explanation=(
                        "Internal temperature variability "
                        f"is elevated at "
                        f"{internal_stability:.2f} °C."
                    ),
                    metric="internal_temperature_stability",
                    value=internal_stability,
                    unit="°C",
                )
            )

        elif internal_stability > 0.40:
            thermal_penalty += 8.0

            findings.append(
                Finding(
                    code="INTERNAL_TEMP_VARIABILITY",
                    severity="MEDIUM",
                    confidence=80.0,
                    explanation=(
                        "Internal temperature variability "
                        f"has reached "
                        f"{internal_stability:.2f} °C."
                    ),
                    metric="internal_temperature_stability",
                    value=internal_stability,
                    unit="°C",
                )
            )

        else:
            findings.append(
                Finding(
                    code="INTERNAL_TEMP_STABILITY_OK",
                    severity="INFO",
                    confidence=95.0,
                    explanation=(
                        "Internal temperature variability "
                        "remains within the provisional "
                        "nominal range."
                    ),
                    metric="internal_temperature_stability",
                    value=internal_stability,
                    unit="°C",
                )
            )

        if compressor_trend > 3.00:
            thermal_penalty += 25.0

            findings.append(
                Finding(
                    code="COMPRESSOR_TEMP_RISING_FAST",
                    severity="HIGH",
                    confidence=90.0,
                    explanation=(
                        "Compressor temperature is rising "
                        f"by {compressor_trend:.2f} °C per hour."
                    ),
                    metric="compressor_temperature_trend",
                    value=compressor_trend,
                    unit="°C/h",
                )
            )

        elif compressor_trend > 1.00:
            thermal_penalty += 10.0

            findings.append(
                Finding(
                    code="COMPRESSOR_TEMP_RISING",
                    severity="MEDIUM",
                    confidence=80.0,
                    explanation=(
                        "A gradual compressor temperature rise "
                        f"of {compressor_trend:.2f} °C per hour "
                        "has been detected."
                    ),
                    metric="compressor_temperature_trend",
                    value=compressor_trend,
                    unit="°C/h",
                )
            )

        else:
            findings.append(
                Finding(
                    code="COMPRESSOR_TEMP_STABLE",
                    severity="INFO",
                    confidence=95.0,
                    explanation=(
                        "Compressor temperature trend is stable."
                    ),
                    metric="compressor_temperature_trend",
                    value=compressor_trend,
                    unit="°C/h",
                )
            )

        if current_trend > 0.20:
            electrical_penalty += 30.0

            findings.append(
                Finding(
                    code="COMPRESSOR_CURRENT_RISING_FAST",
                    severity="HIGH",
                    confidence=90.0,
                    explanation=(
                        "Compressor current is rising "
                        f"by {current_trend:.3f} A per hour."
                    ),
                    metric="compressor_current_trend",
                    value=current_trend,
                    unit="A/h",
                )
            )

        elif current_trend > 0.05:
            electrical_penalty += 12.0

            findings.append(
                Finding(
                    code="COMPRESSOR_CURRENT_RISING",
                    severity="MEDIUM",
                    confidence=80.0,
                    explanation=(
                        "A gradual compressor current increase "
                        f"of {current_trend:.3f} A per hour "
                        "has been detected."
                    ),
                    metric="compressor_current_trend",
                    value=current_trend,
                    unit="A/h",
                )
            )

        else:
            findings.append(
                Finding(
                    code="COMPRESSOR_CURRENT_STABLE",
                    severity="INFO",
                    confidence=95.0,
                    explanation=(
                        "Compressor current trend is stable."
                    ),
                    metric="compressor_current_trend",
                    value=current_trend,
                    unit="A/h",
                )
            )

        baseline_history, current_history = (
            EquipmentBaseline.split_history(history)
        )

        internal_comparison = (
            EquipmentBaseline.compare_metric(
                baseline_history=baseline_history,
                current_history=current_history,
                field="internal_temperature_c",
            )
        )

        compressor_comparison = (
            EquipmentBaseline.compare_metric(
                baseline_history=baseline_history,
                current_history=current_history,
                field="compressor_temperature_c",
            )
        )

        current_comparison = (
            EquipmentBaseline.compare_metric(
                baseline_history=baseline_history,
                current_history=current_history,
                field="compressor_current_a",
            )
        )

        internal_finding, internal_penalty = (
            self._baseline_finding(
                comparison=internal_comparison,
                stable_code="INTERNAL_TEMP_BASELINE_OK",
                warning_code="INTERNAL_TEMP_BASELINE_DRIFT",
                critical_code=(
                    "INTERNAL_TEMP_BASELINE_DEVIATION"
                ),
                label="Internal temperature",
                unit="°C",
            )
        )

        findings.append(internal_finding)
        thermal_penalty += internal_penalty

        compressor_finding, compressor_penalty = (
            self._baseline_finding(
                comparison=compressor_comparison,
                stable_code="COMPRESSOR_TEMP_BASELINE_OK",
                warning_code="COMPRESSOR_TEMP_BASELINE_DRIFT",
                critical_code=(
                    "COMPRESSOR_TEMP_BASELINE_DEVIATION"
                ),
                label="Compressor temperature",
                unit="°C",
            )
        )

        findings.append(compressor_finding)
        thermal_penalty += compressor_penalty

        current_finding, baseline_current_penalty = (
            self._baseline_finding(
                comparison=current_comparison,
                stable_code="COMPRESSOR_CURRENT_BASELINE_OK",
                warning_code="COMPRESSOR_CURRENT_BASELINE_DRIFT",
                critical_code=(
                    "COMPRESSOR_CURRENT_BASELINE_DEVIATION"
                ),
                label="Compressor current",
                unit="A",
            )
        )

        findings.append(current_finding)

        electrical_penalty += (
            baseline_current_penalty
        )

        thermal_score = round(
            max(
                0.0,
                100.0 - thermal_penalty,
            ),
            2,
        )

        electrical_score = round(
            max(
                0.0,
                100.0 - electrical_penalty,
            ),
            2,
        )

        cooling_result = CoolingHealthAnalyzer.analyze(
            history=history,
        )

        sensor_result = SensorHealthAnalyzer.analyze(
            history=history,
        )

        findings.extend(cooling_result.findings)
        findings.extend(sensor_result.findings)

        cooling_score = cooling_result.score
        sensor_score = sensor_result.score

        # Provisional global weighting:
        # 40% thermal behavior
        # 20% electrical behavior
        # 30% cooling performance
        # 10% sensor health
        health_score = round(
            thermal_score * 0.40
            + electrical_score * 0.20
            + cooling_score * 0.30
            + sensor_score * 0.10,
            2,
        )

        status = Rules.status(health_score)

        significant_findings = [
            finding
            for finding in findings
            if finding.severity != "INFO"
        ]

        if not significant_findings:
            analysis = (
                "Historical behavior, cooling performance and "
                "sensor signals remain stable and consistent "
                "with this equipment's baseline."
            )
            recommendation = "No action required."

        elif status == "SURVEILLANCE":
            analysis = (
                "A minor deviation from the equipment "
                "baseline has been detected."
            )
            recommendation = (
                "Continue monitoring the next operating cycles."
            )

        elif status == "ATTENTION":
            analysis = (
                "One or more indicators show a significant "
                "deviation from the equipment baseline."
            )
            recommendation = (
                "Plan a preventive technical inspection."
            )

        else:
            analysis = (
                "Critical degradation relative to the "
                "equipment baseline has been detected."
            )
            recommendation = (
                "Immediate technical inspection is recommended."
            )

        confidence = min(
            95.0,
            50.0 + len(history) / 20.0,
        )

        root_cause_result = RootCauseAnalyzer.analyze(
            findings=findings,
        )

        prediction_result = PredictionEngine.predict(
            thermal_score=thermal_score,
            electrical_score=electrical_score,
            cooling_score=cooling_score,
            sensor_score=sensor_score,
            findings=findings,
            sample_count=len(history),
        )

        if root_cause_result.code != "NO_ANOMALY_DETECTED":
            recommendation = root_cause_result.recommendation

        return AnalysisResult(
            health_score=health_score,
            status=status,
            analysis=analysis,
            recommendation=recommendation,
            confidence=round(confidence, 1),
            thermal_score=thermal_score,
            electrical_score=electrical_score,
            cooling_score=cooling_score,
            sensor_score=sensor_score,
            root_cause_code=root_cause_result.code,
            root_cause=root_cause_result.label,
            root_cause_confidence=root_cause_result.confidence,
            root_cause_explanation=root_cause_result.explanation,
            risk_index=prediction_result.risk_index,
            failure_probability_30d=prediction_result.probability_percent,
            prediction_horizon_days=prediction_result.horizon_days,
            prediction_confidence=prediction_result.confidence,
            prediction_explanation=prediction_result.explanation,
            findings=findings,
        )
