"""Platform for Mazda climate integration."""
from __future__ import annotations

from typing import Any

from pymazda import Client as MazdaAPIClient

from homeassistant.components.climate import (
    ClimateEntity,
    ClimateEntityFeature,
    HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
    ATTR_TEMPERATURE,
    PRECISION_HALVES,
    PRECISION_WHOLE,
    UnitOfTemperature,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.util.unit_conversion import TemperatureConverter

from . import MazdaEntity
from .const import DATA_CLIENT, DATA_COORDINATOR, DATA_REGION, DOMAIN

PRESET_DEFROSTER_OFF = "Defroster Off"
PRESET_DEFROSTER_FRONT = "Front Defroster"
PRESET_DEFROSTER_REAR = "Rear Defroster"
PRESET_DEFROSTER_FRONT_AND_REAR = "Front and Rear Defroster"


def _front_defroster_enabled(preset_mode: str | None) -> bool:
    return preset_mode in [
        PRESET_DEFROSTER_FRONT_AND_REAR,
        PRESET_DEFROSTER_FRONT,
    ]


def _rear_defroster_enabled(preset_mode: str | None) -> bool:
    return preset_mode in [
        PRESET_DEFROSTER_FRONT_AND_REAR,
        PRESET_DEFROSTER_REAR,
    ]


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up the climate platform."""
    entry_data = hass.data[DOMAIN][config_entry.entry_id]
    client = entry_data[DATA_CLIENT]
    coordinator = entry_data[DATA_COORDINATOR]
    region = entry_data[DATA_REGION]

    async_add_entities(
        MazdaClimateEntity(client, coordinator, index, region)
        for index, data in enumerate(coordinator.data)
        if data["isElectric"]
    )


class MazdaClimateEntity(MazdaEntity, ClimateEntity):
    """Class for a Mazda climate entity."""

    _attr_name = "Climate"
    _attr_supported_features = (
        ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
    )
    _attr_hvac_modes = [HVACMode.HEAT_COOL, HVACMode.OFF]
    _attr_preset_modes = [
        PRESET_DEFROSTER_OFF,
        PRESET_DEFROSTER_FRONT,
        PRESET_DEFROSTER_REAR,
        PRESET_DEFROSTER_FRONT_AND_REAR,
    ]

    def __init__(
        self,
        client: MazdaAPIClient,
        coordinator: DataUpdateCoordinator,
        index: int,
        region: str,
    ) -> None:
        """Initialize Mazda climate entity."""
        super().__init__(client, coordinator, index)

        self.region = region
        self._attr_unique_id = self.vin

        if self.data["hvacSetting"]["temperatureUnit"] == "F":
            self._attr_precision = PRECISION_WHOLE
            self._attr_temperature_unit = UnitOfTemperature.FAHRENHEIT
            self._attr_min_temp = 61.0
            self._attr_max_temp = 83.0
        else:
            self._attr_precision = PRECISION_HALVES
            self._attr_temperature_unit = UnitOfTemperature.CELSIUS
            if region == "MJO":
                self._attr_min_temp = 18.5
                self._attr_max_temp = 31.5
            else:
                self._attr_min_temp = 15.5
                self._attr_max_temp = 28.5

        self._update_state_attributes()

    @callback
    def _handle_coordinator_update(self) -> None:
        """Update attributes when the coordinator data updates."""
        self._update_state_attributes()

        super()._handle_coordinator_update()

    def _update_state_attributes(self) -> None:
        # Update the HVAC mode
        hvac_on = self.client.get_assumed_hvac_mode(self.vehicle_id)
        self._attr_hvac_mode = HVACMode.HEAT_COOL if hvac_on else HVACMode.OFF

        # Update the target temperature
        hvac_setting = self.client.get_assumed_hvac_setting(self.vehicle_id)
        self._attr_target_temperature = hvac_setting.get("temperature")

        # Update the current temperature
        current_temperature_celsius = self.data["evStatus"]["hvacInfo"][
            "interiorTemperatureCelsius"
        ]
        if self.data["hvacSetting"]["temperatureUnit"] == "F":
            self._attr_current_temperature = TemperatureConverter.convert(
                current_temperature_celsius,
                UnitOfTemperature.CELSIUS,
                UnitOfTemperature.FAHRENHEIT,
            )
        else:
            self._attr_current_temperature = current_temperature_celsius

        # Update the preset mode based on the state of the front and rear defrosters
        front_defroster = hvac_setting.get("frontDefroster")
        rear_defroster = hvac_setting.get("rearDefroster")
        if front_defroster and rear_defroster:
            self._attr_preset_mode = PRESET_DEFROSTER_FRONT_AND_REAR
        elif front_defroster:
            self._attr_preset_mode = PRESET_DEFROSTER_FRONT
        elif rear_defroster:
            self._attr_preset_mode = PRESET_DEFROSTER_REAR
        else:
            self._attr_preset_mode = PRESET_DEFROSTER_OFF

    async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
        """Set a new HVAC mode."""
        if hvac_mode == HVACMode.HEAT_COOL:
            await self.client.turn_on_hvac(self.vehicle_id)
        elif hvac_mode == HVACMode.OFF:
            await self.client.turn_off_hvac(self.vehicle_id)

        self._handle_coordinator_update()

    async def async_set_temperature(self, **kwargs: Any) -> None:
        """Set a new target temperature."""
        if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None:
            precision = self.precision
            rounded_temperature = round(temperature / precision) * precision

            await self.client.set_hvac_setting(
                self.vehicle_id,
                rounded_temperature,
                self.data["hvacSetting"]["temperatureUnit"],
                _front_defroster_enabled(self._attr_preset_mode),
                _rear_defroster_enabled(self._attr_preset_mode),
            )

            self._handle_coordinator_update()

    async def async_set_preset_mode(self, preset_mode: str) -> None:
        """Turn on/off the front/rear defrosters according to the chosen preset mode."""
        await self.client.set_hvac_setting(
            self.vehicle_id,
            self._attr_target_temperature,
            self.data["hvacSetting"]["temperatureUnit"],
            _front_defroster_enabled(preset_mode),
            _rear_defroster_enabled(preset_mode),
        )

        self._handle_coordinator_update()
