"""Calculator for price volatility analysis."""

from __future__ import annotations

from typing import TYPE_CHECKING

from custom_components.tibber_prices.const import get_display_unit_factor
from custom_components.tibber_prices.entity_utils import add_icon_color_attribute
from custom_components.tibber_prices.sensor.attributes import (
    add_volatility_type_attributes,
    get_prices_for_volatility,
)
from custom_components.tibber_prices.utils.average import calculate_mean
from custom_components.tibber_prices.utils.price import calculate_volatility_with_cv

from .base import TibberPricesBaseCalculator

if TYPE_CHECKING:
    from typing import Any


class TibberPricesVolatilityCalculator(TibberPricesBaseCalculator):
    """
    Calculator for price volatility analysis.

    Calculates volatility levels (low, moderate, high, very_high) using coefficient
    of variation for different time periods (today, tomorrow, next 24h, today+tomorrow).
    """

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        """
        Initialize calculator.

        Args:
            *args: Positional arguments passed to BaseCalculator.
            **kwargs: Keyword arguments passed to BaseCalculator.

        """
        super().__init__(*args, **kwargs)
        self._last_volatility_attributes: dict[str, Any] = {}

    def get_volatility_value(self, *, volatility_type: str) -> str | None:
        """
        Calculate price volatility using coefficient of variation for different time periods.

        Also stores detailed attributes in self._last_volatility_attributes for use in
        extra_state_attributes.

        Args:
            volatility_type: One of "today", "tomorrow", "next_24h", "today_tomorrow".

        Returns:
            Volatility level: "low", "moderate", "high", "very_high", or None if unavailable.

        """
        if not self.has_data():
            return None

        # Get volatility thresholds from config
        thresholds = {
            "threshold_moderate": self.config.get("volatility_threshold_moderate", 5.0),
            "threshold_high": self.config.get("volatility_threshold_high", 15.0),
            "threshold_very_high": self.config.get("volatility_threshold_very_high", 30.0),
        }

        # Get prices based on volatility type
        prices_to_analyze = get_prices_for_volatility(
            volatility_type,
            self.coordinator.data,
            time=self.coordinator.time,
        )

        if not prices_to_analyze:
            return None

        # Calculate spread and basic statistics
        price_min = min(prices_to_analyze)
        price_max = max(prices_to_analyze)
        spread = price_max - price_min
        # Use arithmetic mean for volatility calculation (required for coefficient of variation)
        price_mean = calculate_mean(prices_to_analyze)

        # Convert to display currency unit based on configuration
        factor = get_display_unit_factor(self.config_entry)
        spread_display = spread * factor

        # Calculate volatility level AND coefficient of variation
        volatility, cv = calculate_volatility_with_cv(prices_to_analyze, **thresholds)

        # Store attributes for this sensor
        self._last_volatility_attributes = {
            "price_spread": round(spread_display, 2),
            "price_volatility": volatility,
            "coefficient_of_variation": round(cv, 2) if cv is not None else None,
            "price_min": round(price_min * factor, 2),
            "price_max": round(price_max * factor, 2),
            "price_mean": round(price_mean * factor, 2),  # Mean used for volatility calculation
            "interval_count": len(prices_to_analyze),
        }

        # Add icon_color for dynamic styling
        add_icon_color_attribute(self._last_volatility_attributes, key="volatility", state_value=volatility)

        # Add type-specific attributes
        add_volatility_type_attributes(
            self._last_volatility_attributes,
            volatility_type,
            self.coordinator.data,
            thresholds,
            time=self.coordinator.time,
        )

        # Return lowercase for ENUM device class
        return volatility.lower()

    def get_volatility_attributes(self) -> dict[str, Any]:
        """
        Get stored volatility attributes from last calculation.

        Returns:
            Dictionary of volatility attributes, or empty dict if no calculation yet.

        """
        return self._last_volatility_attributes
