"""
Time-series indicators for Sentinel Brain.
"""

from datetime import datetime
from statistics import pstdev


class TrendIndicators:
    """
    Compute indicators from measurement history.
    """

    @staticmethod
    def _parse_timestamp(timestamp: object) -> datetime:
        """
        Convert a stored timestamp into a datetime.
        """
        value = str(timestamp).strip().replace("Z", "+00:00")

        return datetime.fromisoformat(value)

    @classmethod
    def slope_per_hour(
        cls,
        history: list[dict[str, object]],
        field: str,
    ) -> float:
        """
        Calculate the linear trend of one field per hour.
        """
        valid_rows = [
            row
            for row in history
            if row.get(field) is not None
            and row.get("recorded_at") is not None
        ]

        if len(valid_rows) < 2:
            return 0.0

        first_time = cls._parse_timestamp(
            valid_rows[0]["recorded_at"]
        )

        x_values: list[float] = []
        y_values: list[float] = []

        for row in valid_rows:
            recorded_at = cls._parse_timestamp(
                row["recorded_at"]
            )

            elapsed_hours = (
                recorded_at - first_time
            ).total_seconds() / 3600.0

            x_values.append(elapsed_hours)
            y_values.append(float(row[field]))

        x_mean = sum(x_values) / len(x_values)
        y_mean = sum(y_values) / len(y_values)

        denominator = sum(
            (x_value - x_mean) ** 2
            for x_value in x_values
        )

        if denominator == 0:
            return 0.0

        numerator = sum(
            (x_value - x_mean) * (y_value - y_mean)
            for x_value, y_value in zip(
                x_values,
                y_values,
            )
        )

        return round(numerator / denominator, 4)

    @staticmethod
    def standard_deviation(
        history: list[dict[str, object]],
        field: str,
    ) -> float:
        """
        Calculate population standard deviation for one field.
        """
        values = [
            float(row[field])
            for row in history
            if row.get(field) is not None
        ]

        if len(values) < 2:
            return 0.0

        return round(pstdev(values), 4)

    @classmethod
    def internal_temperature_drift(
        cls,
        history: list[dict[str, object]],
    ) -> float:
        """
        Return internal temperature drift in degrees Celsius per hour.
        """
        return cls.slope_per_hour(
            history=history,
            field="internal_temperature_c",
        )

    @classmethod
    def compressor_temperature_trend(
        cls,
        history: list[dict[str, object]],
    ) -> float:
        """
        Return compressor temperature trend in degrees Celsius per hour.
        """
        return cls.slope_per_hour(
            history=history,
            field="compressor_temperature_c",
        )

    @classmethod
    def compressor_current_trend(
        cls,
        history: list[dict[str, object]],
    ) -> float:
        """
        Return compressor current trend in amperes per hour.
        """
        return cls.slope_per_hour(
            history=history,
            field="compressor_current_a",
        )

    @classmethod
    def internal_temperature_stability(
        cls,
        history: list[dict[str, object]],
    ) -> float:
        """
        Return internal temperature standard deviation.
        """
        return cls.standard_deviation(
            history=history,
            field="internal_temperature_c",
        )