"""Model for the Ecoforest stove status."""
from __future__ import annotations

from dataclasses import dataclass
from enum import Enum

from pyecoforest.const import MODEL_NAME, SUPPORTED_MODELS
from pyecoforest.exceptions import EcoforestError


class OperationMode(Enum):
    """Model that represents the device operation modes."""

    POWER = "power"
    TEMPERATURE = "temperature"
    EMERGENCY = "emergency"

    @classmethod
    def build(cls, mode: str) -> OperationMode:
        """Parse the operation mode code to an OperationMode object."""
        modes = {
            "0": OperationMode.POWER,
            "1": OperationMode.TEMPERATURE,
            "2": OperationMode.EMERGENCY,
        }

        if mode in modes:
            return modes[mode]

        raise EcoforestError(f"The operation mode {mode} is not a valid operation!")


class State(Enum):
    """Model that represents the state of the device."""

    OFF = "off"
    STARTING = "starting"
    PRE_HEATING = "pre_heating"
    ON = "on"
    SHUTTING_DOWN = "shutting_down"
    STAND_BY = "stand_by"
    ALARM = "alarm"

    @classmethod
    def build(cls, state: str) -> State:
        """Parse the state code to a State object."""
        states = {
            "OFF": [0],
            "STARTING": [1, 2, 3, 4, 10],
            "PRE_HEATING": [5, 6],
            "ON": [7],
            "SHUTTING_DOWN": [8, 11, -3],
            "STAND_BY": [-20],
            "ALARM": [-4],
        }

        for k, v in states.items():
            if int(state) in v:
                return State[k]

        raise EcoforestError(f"The state {state} is not a valid state!")


class Alarm(Enum):
    """Model that represents the alarms of the device."""

    AIR_DEPRESSION = "air_depression"
    PELLETS = "pellets"
    CPU_OVERHEATING = "cpu_overheating"
    UNKNOWN = "unknown"

    @classmethod
    def build(cls, alarm: str) -> Alarm | None:
        """Parse the alarm code to an Alarm object."""
        alarms = {
            "A001": Alarm.AIR_DEPRESSION,
            "A002": Alarm.AIR_DEPRESSION,
            "A012": Alarm.CPU_OVERHEATING,
            "A099": Alarm.PELLETS,
            "N": None,
        }

        if alarm in alarms:
            return alarms[alarm]

        return Alarm.UNKNOWN


@dataclass
class Device:
    """Model for the Ecoforest stove."""

    # model information
    is_supported: bool
    firmware: str
    model: str
    model_name: str
    serial_number: str

    # confirguation information
    operation_mode: OperationMode

    # status information
    on: bool
    state: State
    power: int
    temperature: float
    alarm: Alarm | None = None
    alarm_code: str | None = None

    # sensors
    environment_temperature: float | None = None
    cpu_temperature: float | None = None
    gas_temperature: float | None = None
    ntc_temperature: float | None = None
    depression: int | None = None
    working_hours: int | None = None
    working_state: int | None = None
    working_level: int | None = None
    ignitions: int | None = None
    live_pulse: float | None = None
    pulse_offset: float | None = None
    extractor: float | None = None
    convecto_air_flow: float | None = None

    @classmethod
    def build(cls, data: dict[str, dict[str, str]]) -> Device:
        """Parse request data and return as Device."""
        status = data["status"]
        stats = data["stats"]
        alarms = data["alarms"]
        model = stats["Me"]
        return Device(
            is_supported=model in SUPPORTED_MODELS,
            model=model,
            model_name=MODEL_NAME,
            firmware=stats["Vs"],
            serial_number=stats["Ns"],
            operation_mode=OperationMode.build(status["modo_operacion"]),
            on=status["on_off"] == "1",
            state=State.build(status["estado"]),
            power=int(status["consigna_potencia"]),
            temperature=float(status["consigna_temperatura"]),
            alarm=Alarm.build(alarms["get_alarmas"]),
            alarm_code=alarms["get_alarmas"] if alarms["get_alarmas"] != "N" else None,
            environment_temperature=float(status["temperatura"]),
            cpu_temperature=float(stats["Tp"]),
            gas_temperature=float(stats["Th"]),
            ntc_temperature=float(stats["Tn"]),
            depression=int(stats["Da"]),
            working_hours=int(stats["Nh"]),
            ignitions=int(stats["Ne"]),
            live_pulse=float(stats["Pn"]),
            pulse_offset=float(stats["Pf"]),
            working_state=int(stats["Es"]),
            extractor=float(stats["Ex"]),
            working_level=int(stats["Ni"]),
            convecto_air_flow=float(stats["Co"]),
        )
