"""Support for UK Met Office weather service."""

import logging

from homeassistant.const import (
    ATTR_ATTRIBUTION,
    DEVICE_CLASS_HUMIDITY,
    DEVICE_CLASS_TEMPERATURE,
    LENGTH_KILOMETERS,
    SPEED_MILES_PER_HOUR,
    TEMP_CELSIUS,
    UNIT_PERCENTAGE,
    UV_INDEX,
)
from homeassistant.core import callback
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import ConfigType, HomeAssistantType

from .const import (
    ATTRIBUTION,
    CONDITION_CLASSES,
    DOMAIN,
    METOFFICE_COORDINATOR,
    METOFFICE_DATA,
    METOFFICE_NAME,
    VISIBILITY_CLASSES,
    VISIBILITY_DISTANCE_CLASSES,
)

_LOGGER = logging.getLogger(__name__)

ATTR_LAST_UPDATE = "last_update"
ATTR_SENSOR_ID = "sensor_id"
ATTR_SITE_ID = "site_id"
ATTR_SITE_NAME = "site_name"

# Sensor types are defined as:
#   variable -> [0]title, [1]device_class, [2]units, [3]icon, [4]enabled_by_default
SENSOR_TYPES = {
    "name": ["Station Name", None, None, "mdi:label-outline", False],
    "weather": [
        "Weather",
        None,
        None,
        "mdi:weather-sunny",  # but will adapt to current conditions
        True,
    ],
    "temperature": ["Temperature", DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, None, True],
    "feels_like_temperature": [
        "Feels Like Temperature",
        DEVICE_CLASS_TEMPERATURE,
        TEMP_CELSIUS,
        None,
        False,
    ],
    "wind_speed": [
        "Wind Speed",
        None,
        SPEED_MILES_PER_HOUR,
        "mdi:weather-windy",
        True,
    ],
    "wind_direction": ["Wind Direction", None, None, "mdi:compass-outline", False],
    "wind_gust": ["Wind Gust", None, SPEED_MILES_PER_HOUR, "mdi:weather-windy", False],
    "visibility": ["Visibility", None, None, "mdi:eye", False],
    "visibility_distance": [
        "Visibility Distance",
        None,
        LENGTH_KILOMETERS,
        "mdi:eye",
        False,
    ],
    "uv": ["UV Index", None, UV_INDEX, "mdi:weather-sunny-alert", True],
    "precipitation": [
        "Probability of Precipitation",
        None,
        UNIT_PERCENTAGE,
        "mdi:weather-rainy",
        True,
    ],
    "humidity": ["Humidity", DEVICE_CLASS_HUMIDITY, UNIT_PERCENTAGE, None, False],
}


async def async_setup_entry(
    hass: HomeAssistantType, entry: ConfigType, async_add_entities
) -> None:
    """Set up the Met Office weather sensor platform."""
    hass_data = hass.data[DOMAIN][entry.entry_id]

    async_add_entities(
        [
            MetOfficeCurrentSensor(entry.data, hass_data, sensor_type)
            for sensor_type in SENSOR_TYPES
        ],
        False,
    )


class MetOfficeCurrentSensor(Entity):
    """Implementation of a Met Office current weather condition sensor."""

    def __init__(self, entry_data, hass_data, sensor_type):
        """Initialize the sensor."""
        self._data = hass_data[METOFFICE_DATA]
        self._coordinator = hass_data[METOFFICE_COORDINATOR]

        self._type = sensor_type
        self._name = f"{hass_data[METOFFICE_NAME]} {SENSOR_TYPES[self._type][0]}"
        self._unique_id = f"{SENSOR_TYPES[self._type][0]}_{self._data.latitude}_{self._data.longitude}"

        self.metoffice_site_id = None
        self.metoffice_site_name = None
        self.metoffice_now = None

    @property
    def name(self):
        """Return the name of the sensor."""
        return self._name

    @property
    def unique_id(self):
        """Return the unique of the sensor."""
        return self._unique_id

    @property
    def state(self):
        """Return the state of the sensor."""
        value = None

        if self._type == "visibility_distance" and hasattr(
            self.metoffice_now, "visibility"
        ):
            value = VISIBILITY_DISTANCE_CLASSES.get(self.metoffice_now.visibility.value)

        if self._type == "visibility" and hasattr(self.metoffice_now, "visibility"):
            value = VISIBILITY_CLASSES.get(self.metoffice_now.visibility.value)

        elif self._type == "weather" and hasattr(self.metoffice_now, self._type):
            value = [
                k
                for k, v in CONDITION_CLASSES.items()
                if self.metoffice_now.weather.value in v
            ][0]

        elif hasattr(self.metoffice_now, self._type):
            value = getattr(self.metoffice_now, self._type)

            if not isinstance(value, int):
                value = value.value

        return value

    @property
    def unit_of_measurement(self):
        """Return the unit of measurement."""
        return SENSOR_TYPES[self._type][2]

    @property
    def icon(self):
        """Return the icon for the entity card."""
        value = SENSOR_TYPES[self._type][3]
        if self._type == "weather":
            value = self.state
            if value is None:
                value = "sunny"
            elif value == "partlycloudy":
                value = "partly-cloudy"
            value = f"mdi:weather-{value}"

        return value

    @property
    def device_class(self):
        """Return the device class of the sensor."""
        return SENSOR_TYPES[self._type][1]

    @property
    def device_state_attributes(self):
        """Return the state attributes of the device."""
        return {
            ATTR_ATTRIBUTION: ATTRIBUTION,
            ATTR_LAST_UPDATE: self.metoffice_now.date if self.metoffice_now else None,
            ATTR_SENSOR_ID: self._type,
            ATTR_SITE_ID: self.metoffice_site_id if self.metoffice_site_id else None,
            ATTR_SITE_NAME: self.metoffice_site_name
            if self.metoffice_site_name
            else None,
        }

    async def async_added_to_hass(self) -> None:
        """Set up a listener and load data."""
        self.async_on_remove(
            self._coordinator.async_add_listener(self._update_callback)
        )
        self._update_callback()

    async def async_update(self):
        """Schedule a custom update via the common entity update service."""
        await self._coordinator.async_request_refresh()

    @callback
    def _update_callback(self) -> None:
        """Load data from integration."""
        self.metoffice_site_id = self._data.site_id
        self.metoffice_site_name = self._data.site_name
        self.metoffice_now = self._data.now
        self.async_write_ha_state()

    @property
    def should_poll(self) -> bool:
        """Entities do not individually poll."""
        return False

    @property
    def entity_registry_enabled_default(self) -> bool:
        """Return if the entity should be enabled when first added to the entity registry."""
        return SENSOR_TYPES[self._type][4]

    @property
    def available(self):
        """Return if state is available."""
        return self.metoffice_site_id is not None and self.metoffice_now is not None
