"""Module to represent Netatmo modules."""

from __future__ import annotations

from dataclasses import dataclass
import logging
from typing import Any

from pyatmo.const import (
    ACCESSORY_GUST_ANGLE_TYPE,
    ACCESSORY_GUST_STRENGTH_TYPE,
    ACCESSORY_RAIN_24H_TYPE,
    ACCESSORY_RAIN_60MIN_TYPE,
    ACCESSORY_RAIN_LIVE_TYPE,
    ACCESSORY_WIND_ANGLE_TYPE,
    ACCESSORY_WIND_STRENGTH_TYPE,
    STATION_HUMIDITY_TYPE,
    STATION_PRESSURE_TYPE,
    STATION_TEMPERATURE_TYPE,
    RawData,
)
from pyatmo.modules.module import (
    BatteryMixin,
    BoilerMixin,
    Camera,
    CO2Mixin,
    DoorTagCategoryMixin,
    FirmwareMixin,
    FloodlightMixin,
    HealthIndexMixin,
    HLSCameraMixin,
    HumidityMixin,
    Module,
    MonitoringMixin,
    NoiseMixin,
    OpenThermMixin,
    PlaceMixin,
    PressureMixin,
    RainMixin,
    RfMixin,
    SirenMixin,
    StatusMixin,
    TemperatureMixin,
    WebRTCCameraMixin,
    WifiMixin,
    WindMixin,
)

LOG: logging.Logger = logging.getLogger(__name__)


class NRV(FirmwareMixin, RfMixin, BatteryMixin, Module):
    """Class to represent a Netatmo NRV."""


class NAC(FirmwareMixin, RfMixin, BatteryMixin, Module):
    """Class to represent a Netatmo NAC."""


class NATherm1(FirmwareMixin, RfMixin, BatteryMixin, BoilerMixin, Module):
    """Class to represent a Netatmo NATherm1."""


class NAPlug(FirmwareMixin, RfMixin, WifiMixin, Module):
    """Class to represent a Netatmo NAPlug."""


class OTH(FirmwareMixin, WifiMixin, BoilerMixin, OpenThermMixin, Module):
    """Class to represent a Netatmo OTH."""


class OTM(FirmwareMixin, RfMixin, BatteryMixin, BoilerMixin, Module):
    """Class to represent a Netatmo OTM."""


class NACamera(HLSCameraMixin, Camera):
    """Class to represent a Netatmo NACamera."""


class NPC(WebRTCCameraMixin, Camera):
    """Class to represent a Netatmo NPC."""


class NOC(SirenMixin, FloodlightMixin, HLSCameraMixin, Camera):
    """Class to represent a Netatmo NOC."""


class NDB(WebRTCCameraMixin, Camera):
    """Class to represent a Netatmo NDB."""


class NAMain(
    TemperatureMixin,
    HumidityMixin,
    CO2Mixin,
    NoiseMixin,
    PressureMixin,
    WifiMixin,
    FirmwareMixin,
    PlaceMixin,
    Module,
):
    """Class to represent a Netatmo NAMain."""


class NAModule1(
    TemperatureMixin,
    HumidityMixin,
    RfMixin,
    FirmwareMixin,
    BatteryMixin,
    PlaceMixin,
    Module,
):
    """Class to represent a Netatmo NAModule1."""


class NAModule2(WindMixin, RfMixin, FirmwareMixin, BatteryMixin, PlaceMixin, Module):
    """Class to represent a Netatmo NAModule2."""


class NAModule3(RainMixin, RfMixin, FirmwareMixin, BatteryMixin, PlaceMixin, Module):
    """Class to represent a Netatmo NAModule3."""


class NAModule4(
    TemperatureMixin,
    CO2Mixin,
    HumidityMixin,
    RfMixin,
    FirmwareMixin,
    BatteryMixin,
    PlaceMixin,
    Module,
):
    """Class to represent a Netatmo NAModule4."""


class NHC(
    TemperatureMixin,
    HumidityMixin,
    CO2Mixin,
    PressureMixin,
    NoiseMixin,
    HealthIndexMixin,
    WifiMixin,
    FirmwareMixin,
    PlaceMixin,
    Module,
):
    """Class to represent a Netatmo NHC."""


class NACamDoorTag(
    StatusMixin, FirmwareMixin, BatteryMixin, RfMixin, DoorTagCategoryMixin, Module
):
    """Class to represent a Netatmo NACamDoorTag."""


class NIS(
    StatusMixin,
    MonitoringMixin,
    FirmwareMixin,
    BatteryMixin,
    RfMixin,
    Module,
):
    """Class to represent a Netatmo NIS."""


class NSD(
    FirmwareMixin,
    Module,
):
    """Class to represent a Netatmo NSD."""


class NCO(
    FirmwareMixin,
    Module,
):
    """Class to represent a Netatmo NCO."""


@dataclass
class Location:
    """Class of Netatmo public weather location."""

    lat_ne: str
    lon_ne: str
    lat_sw: str
    lon_sw: str


class PublicWeatherArea:
    """Class of Netatmo public weather data."""

    location: Location
    required_data_type: str | None
    filtering: bool
    modules: list[dict[str, Any]]

    def __init__(
        self,
        lat_ne: str,
        lon_ne: str,
        lat_sw: str,
        lon_sw: str,
        required_data_type: str | None = None,
        filtering: bool = False,
    ) -> None:
        """Initialize self."""

        self.location = Location(
            lat_ne,
            lon_ne,
            lat_sw,
            lon_sw,
        )
        self.modules = []
        self.required_data_type = required_data_type
        self.filtering = filtering

    def update(self, raw_data: RawData) -> None:
        """Update public weather area with the latest data."""

        self.modules = list(raw_data.get("public", []))

    def stations_in_area(self) -> int:
        """Return available number of stations in area."""

        return len(self.modules)

    def get_latest_rain(self) -> dict[str, Any]:
        """Return latest rain measures."""
        return self.get_accessory_data(ACCESSORY_RAIN_LIVE_TYPE)

    def get_60_min_rain(self) -> dict[str, Any]:
        """Return 60 min rain measures."""
        return self.get_accessory_data(ACCESSORY_RAIN_60MIN_TYPE)

    def get_24_h_rain(self) -> dict[str, Any]:
        """Return 24 h rain measures."""
        return self.get_accessory_data(ACCESSORY_RAIN_24H_TYPE)

    def get_latest_pressures(self) -> dict[str, Any]:
        """Return latest pressure measures."""
        return self.get_latest_station_measures(STATION_PRESSURE_TYPE)

    def get_latest_temperatures(self) -> dict[str, Any]:
        """Return latest temperature measures."""
        return self.get_latest_station_measures(STATION_TEMPERATURE_TYPE)

    def get_latest_humidities(self) -> dict[str, Any]:
        """Return latest humidity measures."""
        return self.get_latest_station_measures(STATION_HUMIDITY_TYPE)

    def get_latest_wind_strengths(self) -> dict[str, Any]:
        """Return latest wind strength measures."""
        return self.get_accessory_data(ACCESSORY_WIND_STRENGTH_TYPE)

    def get_latest_wind_angles(self) -> dict[str, Any]:
        """Return latest wind angle measures."""
        return self.get_accessory_data(ACCESSORY_WIND_ANGLE_TYPE)

    def get_latest_gust_strengths(self) -> dict[str, Any]:
        """Return latest gust strength measures."""
        return self.get_accessory_data(ACCESSORY_GUST_STRENGTH_TYPE)

    def get_latest_gust_angles(self) -> dict[str, Any]:
        """Return latest gust angle measures."""

        return self.get_accessory_data(ACCESSORY_GUST_ANGLE_TYPE)

    def get_latest_station_measures(self, data_type: str) -> dict[str, Any]:
        """Return latest station measures of a given type."""

        measures: dict[str, Any] = {}
        for station in self.modules:
            for module in station["measures"].values():
                if (
                    "type" in module
                    and data_type in module["type"]
                    and "res" in module
                    and module["res"]
                ):
                    measure_index = module["type"].index(data_type)
                    latest_timestamp = sorted(module["res"], reverse=True)[0]
                    measures[station["_id"]] = module["res"][latest_timestamp][
                        measure_index
                    ]

        return measures

    def get_accessory_data(self, data_type: str) -> dict[str, Any]:
        """Return accessory data of a given type."""

        data: dict[str, Any] = {}
        for station in self.modules:
            for module in station["measures"].values():
                if data_type in module:
                    data[station["_id"]] = module[data_type]

        return data
