"""Models for statistics."""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any

from mashumaro import field_options
from mashumaro.mixins.json import DataClassJSONMixin

from pylamarzocco.const import DoseIndex, DoseMode, WidgetType

from ._general import BaseWidgetOutput, Thing, Widget

_LOGGER = logging.getLogger(__name__)


def _filter_valid_widgets(
    items: list[dict[str, Any] | str], field_name: str
) -> list[dict[str, Any] | str]:
    """Filter items with valid WidgetType codes, logging warnings for invalid ones.
    
    Args:
        items: List of widget dicts or code strings
        field_name: Name of the field being filtered (for logging)
    
    Returns:
        List of items with valid widget codes
    """
    valid_items = []
    for item in items:
        # Extract code - either directly if string, or from 'code' key if dict
        code = item if isinstance(item, str) else item.get("code")
        if code:
            try:
                WidgetType(code)
            except ValueError:
                # Log entire JSON if it's a dict, otherwise just the code
                if isinstance(item, dict):
                    import json
                    _LOGGER.warning(
                        "Unknown widget in field '%s' will be discarded: %s",
                        field_name,
                        json.dumps(item),
                    )
                else:
                    _LOGGER.warning(
                        "Unknown widget code '%s' in field '%s' will be discarded",
                        code,
                        field_name,
                    )
            else:
                valid_items.append(item)
    return valid_items


@dataclass(kw_only=True)
class ThingStatistics(Thing):
    """Statistics model."""

    firmwares: str | None = field(
        default=None,
    )
    selected_widget_codes: list[WidgetType] = field(
        metadata=field_options(
            alias="selectedWidgetCodes",
        ),
        default_factory=list,
    )
    all_widget_codes: list[WidgetType] = field(
        metadata=field_options(
            alias="allWidgetCodes",
        ),
        default_factory=list,
    )
    selected_widgets: list[Widget] = field(
        metadata=field_options(
            alias="selectedWidgets",
        ),
        default_factory=list,
    )

    widgets: dict[WidgetType, BaseWidgetOutput] = field(default_factory=dict)

    @classmethod
    def __pre_deserialize__(cls, d: dict[str, Any]) -> dict[str, Any]:
        # Filter out widgets with unknown codes and log warnings
        valid_widgets = _filter_valid_widgets(
            d.get("selectedWidgets", []), "selectedWidgets"
        )
        
        # Set widget_type for valid widgets
        for item in valid_widgets:
            assert isinstance(item, dict)
            item["output"]["widget_type"] = item["code"]
        
        d["selectedWidgets"] = valid_widgets
        
        # Filter widget code lists using helper
        d["selectedWidgetCodes"] = _filter_valid_widgets(
            d.get("selectedWidgetCodes", []), "selectedWidgetCodes"
        )
        d["allWidgetCodes"] = _filter_valid_widgets(
            d.get("allWidgetCodes", []), "allWidgetCodes"
        )
        
        return d

    @classmethod
    def __post_deserialize__(cls, obj: ThingStatistics) -> ThingStatistics:
        # move the firmware to a dict with type as key
        obj.widgets = {widget.code: widget.output for widget in obj.selected_widgets}
        return obj


@dataclass(kw_only=True)
class CoffeeAndFlushTrend(BaseWidgetOutput):
    """Coffee and flush trend model."""

    widget_type = WidgetType.COFFEE_AND_FLUSH_TREND
    days: int
    timezone: str
    coffees: list[CoffeeHistoryEvent]


@dataclass(kw_only=True)
class CoffeeHistoryEvent(DataClassJSONMixin):
    """Coffee that has been made in the past."""

    timestamp: datetime = field(
        metadata=field_options(
            deserialize=lambda ts: datetime.fromtimestamp(ts / 1000, tz=timezone.utc),
        )
    )
    value: int


@dataclass(kw_only=True)
class LastCoffeeList(BaseWidgetOutput):
    """Last coffees statistics."""

    widget_type = WidgetType.LAST_COFFEE
    last_coffees: list[LastCoffee] = field(
        metadata=field_options(alias="lastCoffees"),
        default_factory=list,
    )


@dataclass(kw_only=True)
class LastCoffee(DataClassJSONMixin):
    """One of the last coffees."""

    time: datetime = field(
        metadata=field_options(
            deserialize=lambda ts: datetime.fromtimestamp(ts / 1000, tz=timezone.utc),
        )
    )
    extraction_seconds: float = field(
        metadata=field_options(alias="extractionSeconds"),
    )
    dose_mode: DoseMode = field(
        metadata=field_options(alias="doseMode"),
    )
    dose_index: DoseIndex = field(
        metadata=field_options(alias="doseIndex"),
    )
    dose_value_numerator: str | None = field(
        metadata=field_options(alias="doseValueNumerator"),
        default=None,
    )


@dataclass(kw_only=True)
class CoffeeAndFlushCounter(BaseWidgetOutput):
    """Coffee counter statistics."""

    widget_type = WidgetType.COFFEE_AND_FLUSH_COUNTER
    total_coffee: int = field(
        metadata=field_options(alias="totalCoffee"),
    )
    total_flush: int = field(
        metadata=field_options(alias="totalFlush"),
    )
