"""Support for Pirate Weather (Dark Sky Compatable) weather service."""

import datetime
import logging
from dataclasses import dataclass, field
from typing import Literal, NamedTuple

import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant.components.sensor import (
    PLATFORM_SCHEMA,
    SensorDeviceClass,
    SensorEntity,
    SensorEntityDescription,
    SensorStateClass,
)
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import (
    ATTR_ATTRIBUTION,
    CONF_API_KEY,
    CONF_LATITUDE,
    CONF_LONGITUDE,
    CONF_MONITORED_CONDITIONS,
    CONF_NAME,
    CONF_SCAN_INTERVAL,
    DEGREE,
    PERCENTAGE,
    UV_INDEX,
    UnitOfDensity,
    UnitOfIrradiance,
    UnitOfLength,
    UnitOfPressure,
    UnitOfSpeed,
    UnitOfTemperature,
    UnitOfVolumetricFlux,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import DiscoveryInfoType, StateType
from homeassistant.util import dt as dt_util

from .const import (
    ALL_CONDITIONS,
    DEFAULT_SCAN_INTERVAL,
    DOMAIN,
    ENTRY_WEATHER_COORDINATOR,
    MANUFACTURER,
    PW_PLATFORM,
    PW_PLATFORMS,
    PW_PREVPLATFORM,
    PW_ROUND,
)
from .weather_update_coordinator import WeatherUpdateCoordinator

_LOGGER = logging.getLogger(__name__)

ATTRIBUTION = "Powered by Pirate Weather"

CONF_FORECAST = "forecast"
CONF_HOURLY_FORECAST = "hourly_forecast"
CONF_LANGUAGE = "language"
CONF_UNITS = "units"

DEFAULT_LANGUAGE = "en"
DEFAULT_NAME = "Pirate Weather"

DEPRECATED_SENSOR_TYPES = {
    "apparent_temperature_max",
    "apparent_temperature_min",
    "temperature_max",
    "temperature_min",
}

MAP_UNIT_SYSTEM: dict[
    Literal["si", "us", "ca", "uk", "uk2"],
    Literal["si_unit", "us_unit", "ca_unit", "uk_unit", "uk2_unit"],
] = {
    "si": "si_unit",
    "us": "us_unit",
    "ca": "ca_unit",
    "uk": "uk_unit",
    "uk2": "uk2_unit",
}


@dataclass
class PirateWeatherSensorEntityDescription(SensorEntityDescription):
    """Describes Pirate Weather sensor entity."""

    si_unit: str | None = None
    us_unit: str | None = None
    ca_unit: str | None = None
    uk_unit: str | None = None
    uk2_unit: str | None = None
    forecast_mode: list[str] = field(default_factory=list)


# Sensor Types
SENSOR_TYPES: dict[str, PirateWeatherSensorEntityDescription] = {
    "summary": PirateWeatherSensorEntityDescription(
        key="summary",
        name="Summary",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "minutely_summary": PirateWeatherSensorEntityDescription(
        key="minutely_summary",
        name="Minutely Summary",
        forecast_mode=[],
    ),
    "hourly_summary": PirateWeatherSensorEntityDescription(
        key="hourly_summary",
        name="Hourly Summary",
        forecast_mode=[],
    ),
    "daily_summary": PirateWeatherSensorEntityDescription(
        key="daily_summary",
        name="Daily Summary",
        forecast_mode=[],
    ),
    "icon": PirateWeatherSensorEntityDescription(
        key="icon",
        name="Icon",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "nearest_storm_distance": PirateWeatherSensorEntityDescription(
        key="nearest_storm_distance",
        name="Nearest Storm Distance",
        si_unit=UnitOfLength.KILOMETERS,
        us_unit=UnitOfLength.MILES,
        ca_unit=UnitOfLength.KILOMETERS,
        uk_unit=UnitOfLength.KILOMETERS,
        uk2_unit=UnitOfLength.MILES,
        suggested_display_precision=2,
        icon="mdi:weather-lightning",
        forecast_mode=["currently"],
    ),
    "nearest_storm_bearing": PirateWeatherSensorEntityDescription(
        key="nearest_storm_bearing",
        name="Nearest Storm Bearing",
        si_unit=DEGREE,
        us_unit=DEGREE,
        ca_unit=DEGREE,
        uk_unit=DEGREE,
        uk2_unit=DEGREE,
        suggested_display_precision=0,
        icon="mdi:weather-lightning",
        forecast_mode=["currently"],
    ),
    "precip_type": PirateWeatherSensorEntityDescription(
        key="precip_type",
        name="Precip",
        icon="mdi:weather-pouring",
        forecast_mode=["currently", "minutely", "hourly", "daily"],
    ),
    "precip_intensity": PirateWeatherSensorEntityDescription(
        key="precip_intensity",
        name="Precip Intensity",
        device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
        ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        suggested_display_precision=4,
        icon="mdi:weather-rainy",
        forecast_mode=["currently", "minutely", "hourly", "daily"],
    ),
    "precip_probability": PirateWeatherSensorEntityDescription(
        key="precip_probability",
        name="Precip Probability",
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=PERCENTAGE,
        us_unit=PERCENTAGE,
        ca_unit=PERCENTAGE,
        uk_unit=PERCENTAGE,
        uk2_unit=PERCENTAGE,
        suggested_display_precision=0,
        icon="mdi:water-percent",
        forecast_mode=["currently", "minutely", "hourly", "daily"],
    ),
    "precip_accumulation": PirateWeatherSensorEntityDescription(
        key="precip_accumulation",
        name="Precip Accumulation",
        device_class=SensorDeviceClass.PRECIPITATION,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfLength.CENTIMETERS,
        us_unit=UnitOfLength.INCHES,
        ca_unit=UnitOfLength.CENTIMETERS,
        uk_unit=UnitOfLength.CENTIMETERS,
        uk2_unit=UnitOfLength.CENTIMETERS,
        suggested_display_precision=4,
        icon="mdi:weather-snowy",
        forecast_mode=["hourly", "daily"],
    ),
    "liquid_accumulation": PirateWeatherSensorEntityDescription(
        key="liquid_accumulation",
        name="Liquid Accumulation",
        device_class=SensorDeviceClass.PRECIPITATION,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfLength.CENTIMETERS,
        us_unit=UnitOfLength.INCHES,
        ca_unit=UnitOfLength.CENTIMETERS,
        uk_unit=UnitOfLength.CENTIMETERS,
        uk2_unit=UnitOfLength.CENTIMETERS,
        suggested_display_precision=4,
        icon="mdi:weather-rainy",
        forecast_mode=["hourly", "daily"],
    ),
    "snow_accumulation": PirateWeatherSensorEntityDescription(
        key="snow_accumulation",
        name="Snow Accumulation",
        device_class=SensorDeviceClass.PRECIPITATION,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfLength.CENTIMETERS,
        us_unit=UnitOfLength.INCHES,
        ca_unit=UnitOfLength.CENTIMETERS,
        uk_unit=UnitOfLength.CENTIMETERS,
        uk2_unit=UnitOfLength.CENTIMETERS,
        suggested_display_precision=4,
        icon="mdi:weather-snowy",
        forecast_mode=["hourly", "daily"],
    ),
    "ice_accumulation": PirateWeatherSensorEntityDescription(
        key="ice_accumulation",
        name="Ice Accumulation",
        device_class=SensorDeviceClass.PRECIPITATION,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfLength.CENTIMETERS,
        us_unit=UnitOfLength.INCHES,
        ca_unit=UnitOfLength.CENTIMETERS,
        uk_unit=UnitOfLength.CENTIMETERS,
        uk2_unit=UnitOfLength.CENTIMETERS,
        suggested_display_precision=4,
        icon="mdi:weather-snowy-rainy",
        forecast_mode=["hourly", "daily"],
    ),
    "current_day_liquid": PirateWeatherSensorEntityDescription(
        key="current_day_liquid",
        name="Current Day Liquid Accumulation",
        device_class=SensorDeviceClass.PRECIPITATION,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfLength.CENTIMETERS,
        us_unit=UnitOfLength.INCHES,
        ca_unit=UnitOfLength.CENTIMETERS,
        uk_unit=UnitOfLength.CENTIMETERS,
        uk2_unit=UnitOfLength.CENTIMETERS,
        suggested_display_precision=4,
        icon="mdi:weather-rainy",
        forecast_mode=["currently"],
    ),
    "current_day_snow": PirateWeatherSensorEntityDescription(
        key="current_day_snow",
        name="Current Day Snow Accumulation",
        device_class=SensorDeviceClass.PRECIPITATION,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfLength.CENTIMETERS,
        us_unit=UnitOfLength.INCHES,
        ca_unit=UnitOfLength.CENTIMETERS,
        uk_unit=UnitOfLength.CENTIMETERS,
        uk2_unit=UnitOfLength.CENTIMETERS,
        suggested_display_precision=4,
        icon="mdi:weather-snowy",
        forecast_mode=["currently"],
    ),
    "current_day_ice": PirateWeatherSensorEntityDescription(
        key="current_day_ice",
        name="Current Day Ice Accumulation",
        device_class=SensorDeviceClass.PRECIPITATION,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfLength.CENTIMETERS,
        us_unit=UnitOfLength.INCHES,
        ca_unit=UnitOfLength.CENTIMETERS,
        uk_unit=UnitOfLength.CENTIMETERS,
        uk2_unit=UnitOfLength.CENTIMETERS,
        suggested_display_precision=4,
        icon="mdi:weather-snowy-rainy",
        forecast_mode=["currently"],
    ),
    "temperature": PirateWeatherSensorEntityDescription(
        key="temperature",
        name="Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["currently", "hourly"],
    ),
    "apparent_temperature": PirateWeatherSensorEntityDescription(
        key="apparent_temperature",
        name="Apparent Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["currently", "hourly"],
    ),
    "dew_point": PirateWeatherSensorEntityDescription(
        key="dew_point",
        name="Dew Point",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "wind_speed": PirateWeatherSensorEntityDescription(
        key="wind_speed",
        name="Wind Speed",
        device_class=SensorDeviceClass.WIND_SPEED,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfSpeed.METERS_PER_SECOND,
        us_unit=UnitOfSpeed.MILES_PER_HOUR,
        ca_unit=UnitOfSpeed.KILOMETERS_PER_HOUR,
        uk_unit=UnitOfSpeed.MILES_PER_HOUR,
        uk2_unit=UnitOfSpeed.MILES_PER_HOUR,
        suggested_display_precision=2,
        icon="mdi:weather-windy",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "wind_bearing": PirateWeatherSensorEntityDescription(
        key="wind_bearing",
        name="Wind Bearing",
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=DEGREE,
        us_unit=DEGREE,
        ca_unit=DEGREE,
        uk_unit=DEGREE,
        uk2_unit=DEGREE,
        suggested_display_precision=0,
        icon="mdi:compass",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "wind_gust": PirateWeatherSensorEntityDescription(
        key="wind_gust",
        name="Wind Gust",
        device_class=SensorDeviceClass.WIND_SPEED,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfSpeed.METERS_PER_SECOND,
        us_unit=UnitOfSpeed.MILES_PER_HOUR,
        ca_unit=UnitOfSpeed.KILOMETERS_PER_HOUR,
        uk_unit=UnitOfSpeed.MILES_PER_HOUR,
        uk2_unit=UnitOfSpeed.MILES_PER_HOUR,
        suggested_display_precision=2,
        icon="mdi:weather-windy-variant",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "cloud_cover": PirateWeatherSensorEntityDescription(
        key="cloud_cover",
        name="Cloud Coverage",
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=PERCENTAGE,
        us_unit=PERCENTAGE,
        ca_unit=PERCENTAGE,
        uk_unit=PERCENTAGE,
        uk2_unit=PERCENTAGE,
        suggested_display_precision=0,
        icon="mdi:weather-partly-cloudy",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "humidity": PirateWeatherSensorEntityDescription(
        key="humidity",
        name="Humidity",
        device_class=SensorDeviceClass.HUMIDITY,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=PERCENTAGE,
        us_unit=PERCENTAGE,
        ca_unit=PERCENTAGE,
        uk_unit=PERCENTAGE,
        uk2_unit=PERCENTAGE,
        suggested_display_precision=0,
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "pressure": PirateWeatherSensorEntityDescription(
        key="pressure",
        name="Pressure",
        device_class=SensorDeviceClass.PRESSURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfPressure.MBAR,
        us_unit=UnitOfPressure.MBAR,
        ca_unit=UnitOfPressure.MBAR,
        uk_unit=UnitOfPressure.MBAR,
        uk2_unit=UnitOfPressure.MBAR,
        suggested_display_precision=2,
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "visibility": PirateWeatherSensorEntityDescription(
        key="visibility",
        name="Visibility",
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfLength.KILOMETERS,
        us_unit=UnitOfLength.MILES,
        ca_unit=UnitOfLength.KILOMETERS,
        uk_unit=UnitOfLength.KILOMETERS,
        uk2_unit=UnitOfLength.MILES,
        suggested_display_precision=2,
        icon="mdi:eye",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "ozone": PirateWeatherSensorEntityDescription(
        key="ozone",
        name="Ozone",
        state_class=SensorStateClass.MEASUREMENT,
        si_unit="DU",
        us_unit="DU",
        ca_unit="DU",
        uk_unit="DU",
        uk2_unit="DU",
        suggested_display_precision=2,
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "fire_index": PirateWeatherSensorEntityDescription(
        key="fire_index",
        name="Fire Index",
        state_class=SensorStateClass.MEASUREMENT,
        suggested_display_precision=2,
        icon="mdi:fire",
        forecast_mode=["currently", "hourly"],
    ),
    "fire_risk_level": PirateWeatherSensorEntityDescription(
        key="fire_risk_level",
        name="Fire Risk Level",
        device_class=SensorDeviceClass.ENUM,
        icon="mdi:fire",
        forecast_mode=["currently", "hourly", "daily"],
        options=["Extreme", "Very High", "High", "Moderate", "Low", "N/A"],
    ),
    "fire_index_max": PirateWeatherSensorEntityDescription(
        key="fire_index_max",
        name="Fire Index Max",
        state_class=SensorStateClass.MEASUREMENT,
        suggested_display_precision=2,
        icon="mdi:fire",
        forecast_mode=["daily"],
    ),
    "smoke": PirateWeatherSensorEntityDescription(
        key="smoke",
        name="Smoke",
        device_class=SensorDeviceClass.PM25,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        us_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        ca_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        uk_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        uk2_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        suggested_display_precision=2,
        icon="mdi:smoke",
        forecast_mode=["currently", "hourly"],
    ),
    "smoke_max": PirateWeatherSensorEntityDescription(
        key="smoke_max",
        name="Smoke Max",
        device_class=SensorDeviceClass.PM25,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        us_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        ca_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        uk_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        uk2_unit=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
        suggested_display_precision=2,
        icon="mdi:smoke",
        forecast_mode=["daily"],
    ),
    "apparent_temperature_max": PirateWeatherSensorEntityDescription(
        key="apparent_temperature_max",
        name="Daily High Apparent Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["daily"],
    ),
    "apparent_temperature_high": PirateWeatherSensorEntityDescription(
        key="apparent_temperature_high",
        name="Daytime High Apparent Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["daily"],
    ),
    "apparent_temperature_high_time": PirateWeatherSensorEntityDescription(
        key="apparent_temperature_high_time",
        name="Daytime High Apparent Temperature Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=["daily"],
    ),
    "apparent_temperature_min": PirateWeatherSensorEntityDescription(
        key="apparent_temperature_min",
        name="Daily Low Apparent Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["daily"],
    ),
    "apparent_temperature_low": PirateWeatherSensorEntityDescription(
        key="apparent_temperature_low",
        name="Overnight Low Apparent Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["daily"],
    ),
    "apparent_temperature_low_time": PirateWeatherSensorEntityDescription(
        key="apparent_temperature_low_time",
        name="Overnight Low Apparent Temperature Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=["daily"],
    ),
    "temperature_max": PirateWeatherSensorEntityDescription(
        key="temperature_max",
        name="Daily High Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["daily"],
    ),
    "temperature_high": PirateWeatherSensorEntityDescription(
        key="temperature_high",
        name="Daytime High Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["daily"],
    ),
    "temperature_high_time": PirateWeatherSensorEntityDescription(
        key="temperature_high_time",
        name="Daytime High Temperature Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=["daily"],
    ),
    "temperature_min": PirateWeatherSensorEntityDescription(
        key="temperature_min",
        name="Daily Low Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["daily"],
    ),
    "temperature_min_time": PirateWeatherSensorEntityDescription(
        key="temperature_min_time",
        name="Daily Low Temperature Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=["daily"],
    ),
    "temperature_low": PirateWeatherSensorEntityDescription(
        key="temperature_low",
        name="Overnight Low Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfTemperature.CELSIUS,
        us_unit=UnitOfTemperature.FAHRENHEIT,
        ca_unit=UnitOfTemperature.CELSIUS,
        uk_unit=UnitOfTemperature.CELSIUS,
        uk2_unit=UnitOfTemperature.CELSIUS,
        suggested_display_precision=2,
        forecast_mode=["daily"],
    ),
    "precip_intensity_max": PirateWeatherSensorEntityDescription(
        key="precip_intensity_max",
        name="Daily Max Precip Intensity",
        device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
        ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        suggested_display_precision=2,
        icon="mdi:thermometer",
        forecast_mode=["daily"],
    ),
    "uv_index": PirateWeatherSensorEntityDescription(
        key="uv_index",
        name="UV Index",
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UV_INDEX,
        us_unit=UV_INDEX,
        ca_unit=UV_INDEX,
        uk_unit=UV_INDEX,
        uk2_unit=UV_INDEX,
        suggested_display_precision=2,
        icon="mdi:weather-sunny",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "air_quality_index": PirateWeatherSensorEntityDescription(
        key="air_quality_index",
        name="Air Quality Index",
        device_class=SensorDeviceClass.AQI,
        state_class=SensorStateClass.MEASUREMENT,
        suggested_display_precision=0,
        icon="mdi:air-filter",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "cape": PirateWeatherSensorEntityDescription(
        key="cape",
        name="Convective Available Potential Energy",
        state_class=SensorStateClass.MEASUREMENT,
        suggested_display_precision=0,
        icon="mdi:weather-lightning",
        forecast_mode=["currently", "hourly"],
    ),
    "cape_max": PirateWeatherSensorEntityDescription(
        key="cape_max",
        name="Convective Available Potential Energy Max",
        state_class=SensorStateClass.MEASUREMENT,
        suggested_display_precision=0,
        icon="mdi:weather-lightning",
        forecast_mode=["daily"],
    ),
    "solar": PirateWeatherSensorEntityDescription(
        key="solar",
        name="Downward Short-Wave Radiation Flux",
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        us_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        ca_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        uk_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        uk2_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        suggested_display_precision=2,
        icon="mdi:weather-sunny",
        forecast_mode=["currently", "hourly"],
    ),
    "solar_max": PirateWeatherSensorEntityDescription(
        key="solar_max",
        name="Downward Short-Wave Radiation Flux Max",
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        us_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        ca_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        uk_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        uk2_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
        suggested_display_precision=2,
        icon="mdi:weather-sunny",
        forecast_mode=["daily"],
    ),
    "rain_intensity": PirateWeatherSensorEntityDescription(
        key="rain_intensity",
        name="Rain Intensity",
        device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
        ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        suggested_display_precision=4,
        icon="mdi:weather-rainy",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "rain_intensity_max": PirateWeatherSensorEntityDescription(
        key="rain_intensity_max",
        name="Rain Intensity Max",
        device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
        ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        suggested_display_precision=4,
        icon="mdi:weather-rainy",
        forecast_mode=["daily"],
    ),
    "snow_intensity": PirateWeatherSensorEntityDescription(
        key="snow_intensity",
        name="Snow Intensity",
        device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
        ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        suggested_display_precision=4,
        icon="mdi:weather-snowy",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "snow_intensity_max": PirateWeatherSensorEntityDescription(
        key="snow_intensity_max",
        name="Snow Intensity Max",
        device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
        ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        suggested_display_precision=4,
        icon="mdi:weather-snowy",
        forecast_mode=["daily"],
    ),
    "ice_intensity": PirateWeatherSensorEntityDescription(
        key="ice_intensity",
        name="Ice Intensity",
        device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
        ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        suggested_display_precision=4,
        icon="mdi:weather-snowy-rainy",
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "ice_intensity_max": PirateWeatherSensorEntityDescription(
        key="ice_intensity_max",
        name="Ice Intensity Max",
        device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
        state_class=SensorStateClass.MEASUREMENT,
        si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
        ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
        suggested_display_precision=4,
        icon="mdi:weather-snowy-rainy",
        forecast_mode=["daily"],
    ),
    "moon_phase": PirateWeatherSensorEntityDescription(
        key="moon_phase",
        name="Moon Phase",
        suggested_display_precision=2,
        icon="mdi:weather-night",
        forecast_mode=["daily"],
    ),
    "sunrise_time": PirateWeatherSensorEntityDescription(
        key="sunrise_time",
        name="Sunrise",
        icon="mdi:white-balance-sunny",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=["daily"],
    ),
    "sunset_time": PirateWeatherSensorEntityDescription(
        key="sunset_time",
        name="Sunset",
        icon="mdi:weather-night",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=["daily"],
    ),
    "alerts": PirateWeatherSensorEntityDescription(
        key="alerts",
        name="Alerts",
        icon="mdi:alert-circle-outline",
        forecast_mode=[],
    ),
    "time": PirateWeatherSensorEntityDescription(
        key="time",
        name="Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=["currently", "hourly", "daily"],
    ),
    "hrrr_subh_update_time": PirateWeatherSensorEntityDescription(
        key="hrrr_subh",
        name="HRRR SubHourly Update Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=[],
    ),
    "hrrr_0_18_update_time": PirateWeatherSensorEntityDescription(
        key="hrrr_0-18",
        name="HRRR 0-18 Update Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=[],
    ),
    "nbm_update_time": PirateWeatherSensorEntityDescription(
        key="nbm",
        name="NBM Update Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=[],
    ),
    "nbm_fire_update_time": PirateWeatherSensorEntityDescription(
        key="nbm_fire",
        name="NBM Fire Update Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=[],
    ),
    "hrrr_18_48_update_time": PirateWeatherSensorEntityDescription(
        key="hrrr_18-48",
        name="HRRR 18-48 Update Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=[],
    ),
    "gfs_update_time": PirateWeatherSensorEntityDescription(
        key="gfs",
        name="GFS Update Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=[],
    ),
    "gefs_update_time": PirateWeatherSensorEntityDescription(
        key="gefs",
        name="GEFS  Update Time",
        icon="mdi:clock-time-three-outline",
        device_class=SensorDeviceClass.TIMESTAMP,
        forecast_mode=[],
    ),
}


class ConditionPicture(NamedTuple):
    """Entity picture and icon for condition."""

    entity_picture: str
    icon: str


CONDITION_PICTURES: dict[str, ConditionPicture] = {
    "clear-day": ConditionPicture(
        entity_picture="/static/images/darksky/weather-sunny.svg",
        icon="mdi:weather-sunny",
    ),
    "clear-night": ConditionPicture(
        entity_picture="/static/images/darksky/weather-night.svg",
        icon="mdi:weather-night",
    ),
    "rain": ConditionPicture(
        entity_picture="/static/images/darksky/weather-pouring.svg",
        icon="mdi:weather-pouring",
    ),
    "snow": ConditionPicture(
        entity_picture="/static/images/darksky/weather-snowy.svg",
        icon="mdi:weather-snowy",
    ),
    "sleet": ConditionPicture(
        entity_picture="/static/images/darksky/weather-hail.svg",
        icon="mdi:weather-snowy-rainy",
    ),
    "wind": ConditionPicture(
        entity_picture="/static/images/darksky/weather-windy.svg",
        icon="mdi:weather-windy",
    ),
    "fog": ConditionPicture(
        entity_picture="/static/images/darksky/weather-fog.svg",
        icon="mdi:weather-fog",
    ),
    "cloudy": ConditionPicture(
        entity_picture="/static/images/darksky/weather-cloudy.svg",
        icon="mdi:weather-cloudy",
    ),
    "partly-cloudy-day": ConditionPicture(
        entity_picture="/static/images/darksky/weather-partlycloudy.svg",
        icon="mdi:weather-partly-cloudy",
    ),
    "partly-cloudy-night": ConditionPicture(
        entity_picture="/static/images/darksky/weather-cloudy.svg",
        icon="mdi:weather-night-partly-cloudy",
    ),
}


# Language Supported Codes
LANGUAGE_CODES = [
    "ar",
    "az",
    "be",
    "bg",
    "bn",
    "bs",
    "ca",
    "cs",
    "da",
    "de",
    "el",
    "en",
    "ja",
    "ka",
    "kn",
    "ko",
    "eo",
    "es",
    "et",
    "fi",
    "fr",
    "he",
    "hi",
    "hr",
    "hu",
    "id",
    "is",
    "it",
    "kw",
    "lv",
    "ml",
    "mr",
    "nb",
    "nl",
    "pa",
    "pl",
    "pt",
    "ro",
    "ru",
    "sk",
    "sl",
    "sr",
    "sv",
    "ta",
    "te",
    "tet",
    "tr",
    "uk",
    "ur",
    "x-pig-latin",
    "zh",
    "zh-tw",
]

ALLOWED_UNITS = ["si", "us", "ca", "uk", "uk2"]

ALERTS_ATTRS = ["time", "description", "expires", "severity", "uri", "regions", "title"]

HOURS = list(range(168))
DAYS = list(range(7))

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
    {
        vol.Required(CONF_API_KEY): cv.string,
        vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
        vol.Optional(CONF_UNITS): vol.In(ALLOWED_UNITS),
        vol.Optional(CONF_LANGUAGE, default=DEFAULT_LANGUAGE): vol.In(LANGUAGE_CODES),
        vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): cv.time_period,
        vol.Inclusive(
            CONF_LATITUDE, "coordinates", "Latitude and longitude must exist together"
        ): cv.latitude,
        vol.Inclusive(
            CONF_LONGITUDE, "coordinates", "Latitude and longitude must exist together"
        ): cv.longitude,
        vol.Optional(PW_PLATFORM): cv.multi_select(PW_PLATFORMS),
        vol.Optional(PW_PREVPLATFORM): cv.string,
        vol.Optional(CONF_FORECAST): cv.multi_select(DAYS),
        vol.Optional(CONF_HOURLY_FORECAST): cv.multi_select(HOURS),
        vol.Optional(CONF_MONITORED_CONDITIONS, default=None): cv.multi_select(
            ALL_CONDITIONS
        ),
    }
)


async def async_setup_platform(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType | None = None,
) -> None:
    """Import the platform into a config entry."""
    _LOGGER.warning(
        "Configuration of Pirate Weather sensor in YAML is deprecated "
        "Your existing configuration has been imported into the UI automatically "
        "and can be safely removed from your configuration.yaml file"
    )

    # Define as a sensor platform
    config_entry[PW_PLATFORM] = [PW_PLATFORMS[0]]

    # Set as no rounding for compatability
    config_entry[PW_ROUND] = "No"

    hass.async_create_task(
        hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_IMPORT}, data=config_entry
        )
    )


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up Pirate Weather sensor entities based on a config entry."""
    domain_data = hass.data[DOMAIN][config_entry.entry_id]

    name = domain_data[CONF_NAME]
    weather_coordinator = domain_data[ENTRY_WEATHER_COORDINATOR]
    conditions = domain_data[CONF_MONITORED_CONDITIONS]
    forecast_days = domain_data[CONF_FORECAST]
    forecast_hours = domain_data[CONF_HOURLY_FORECAST]
    service_id = config_entry.unique_id or config_entry.entry_id

    # Round Output
    output_round = domain_data[PW_ROUND]

    sensors: list[PirateWeatherSensor] = []

    for condition in conditions:
        # Save units for conversion later
        request_units = domain_data[CONF_UNITS]

        sensor_description = SENSOR_TYPES[condition]

        if condition in DEPRECATED_SENSOR_TYPES:
            _LOGGER.warning("Monitored condition %s is deprecated", condition)

        if (
            not sensor_description.forecast_mode
            or "currently" in sensor_description.forecast_mode
        ):
            unique_id = f"{config_entry.unique_id}-sensor-{condition}"
            sensors.append(
                PirateWeatherSensor(
                    weather_coordinator,
                    condition,
                    name,
                    unique_id,
                    forecast_day=None,
                    forecast_hour=None,
                    description=sensor_description,
                    request_units=request_units,
                    output_round=output_round,
                    service_id=service_id,
                )
            )

        if forecast_days is not None and "daily" in sensor_description.forecast_mode:
            for forecast_day in forecast_days:
                unique_id = (
                    f"{config_entry.unique_id}-sensor-{condition}-daily-{forecast_day}"
                )
                sensors.append(
                    PirateWeatherSensor(
                        weather_coordinator,
                        condition,
                        name,
                        unique_id,
                        forecast_day=int(forecast_day),
                        forecast_hour=None,
                        description=sensor_description,
                        request_units=request_units,
                        output_round=output_round,
                        service_id=service_id,
                    )
                )

        if forecast_hours is not None and "hourly" in sensor_description.forecast_mode:
            for forecast_h in forecast_hours:
                unique_id = (
                    f"{config_entry.unique_id}-sensor-{condition}-hourly-{forecast_h}"
                )
                sensors.append(
                    PirateWeatherSensor(
                        weather_coordinator,
                        condition,
                        name,
                        unique_id,
                        forecast_day=None,
                        forecast_hour=int(forecast_h),
                        description=sensor_description,
                        request_units=request_units,
                        output_round=output_round,
                        service_id=service_id,
                    )
                )

    async_add_entities(sensors)


class PirateWeatherSensor(SensorEntity):
    """Class for an Pirate Weather sensor."""

    # _attr_should_poll = False
    _attr_attribution = ATTRIBUTION
    entity_description: PirateWeatherSensorEntityDescription

    def __init__(  # noqa: PLR0917
        self,
        weather_coordinator: WeatherUpdateCoordinator,
        condition: str,
        name: str,
        unique_id,
        forecast_day: int,
        forecast_hour: int,
        description: PirateWeatherSensorEntityDescription,
        request_units: str,
        output_round: str,
        service_id: str,
    ) -> None:
        """Initialize the sensor."""
        self.client_name = name

        self.entity_description = description
        self.description = description

        self._weather_coordinator = weather_coordinator

        self._attr_unique_id = unique_id
        self._attr_name = name
        self._attr_device_info = DeviceInfo(
            entry_type=DeviceEntryType.SERVICE,
            identifiers={(DOMAIN, service_id)},
            manufacturer=MANUFACTURER,
            name=name,
        )

        self.forecast_day = forecast_day
        self.forecast_hour = forecast_hour
        self.request_units = request_units
        self.output_round = output_round
        self.type = condition
        self._icon = None
        self._alerts = None

        self._name = description.name

    @property
    def name(self):
        """Return the name of the sensor."""
        if self.forecast_day is not None:
            return f"{self.client_name} {self._name} {self.forecast_day}d"
        if self.forecast_hour is not None:
            return f"{self.client_name} {self._name} {self.forecast_hour}h"
        return f"{self.client_name} {self._name}"

    @property
    def available(self) -> bool:
        """Return if weather data is available from Pirate Weather."""
        return self._weather_coordinator.data is not None

    @property
    def attribution(self):
        """Return the attribution."""
        return ATTRIBUTION

    @property
    def native_unit_of_measurement(self):
        """Return the unit of measurement of this entity, if any."""
        unit_key = MAP_UNIT_SYSTEM.get(self.unit_system, "si_unit")
        self._attr_native_unit_of_measurement = getattr(
            self.entity_description, unit_key
        )
        return self._attr_native_unit_of_measurement

    @property
    def unit_system(self):
        """Return the unit system of this entity."""
        return self.request_units

    @property
    def entity_picture(self) -> str | None:
        """Return the entity picture to use in the frontend, if any."""
        if self._icon is None or "summary" not in self.entity_description.key:
            return None

        if self._icon in CONDITION_PICTURES:
            return CONDITION_PICTURES[self._icon].entity_picture

        return None

    def update_unit_of_measurement(self) -> None:
        """Update units based on unit system."""
        unit_key = MAP_UNIT_SYSTEM.get(self.unit_system, "si_unit")
        self._attr_native_unit_of_measurement = getattr(
            self.entity_description, unit_key
        )

    @property
    def icon(self) -> str | None:
        """Icon to use in the frontend, if any."""
        if (
            "summary" in self.entity_description.key
            and self._icon in CONDITION_PICTURES
        ):
            return CONDITION_PICTURES[self._icon].icon

        return self.entity_description.icon

    @property
    def extra_state_attributes(self):
        """Return the state attributes."""
        if self.type == "alerts":
            extra_attr = self._alerts
            extra_attr[ATTR_ATTRIBUTION] = ATTRIBUTION
        else:
            extra_attr = {ATTR_ATTRIBUTION: ATTRIBUTION}
        return extra_attr

    @property
    def native_value(self) -> StateType:
        """Return the state of the device."""
        self.update_unit_of_measurement()

        if self.type == "alerts":
            data = self._weather_coordinator.data.alerts()

            alerts = {}
            if data is None:
                self._alerts = alerts
                return data

            multiple_alerts = len(data) > 1
            for i, alert in enumerate(data):
                for attr in ALERTS_ATTRS:
                    if multiple_alerts:
                        dkey = f"{attr}_{i!s}"
                    else:
                        dkey = attr
                    alerts_attr = getattr(alert, attr)

                    # Convert time to string using dt_util
                    if isinstance(alerts_attr, int):
                        alerts_attr = dt_util.as_local(
                            dt_util.utc_from_timestamp(alerts_attr)
                        ).isoformat()

                    alerts[dkey] = alerts_attr

            self._alerts = alerts
            native_val = len(data)

        elif self.type in [
            "hrrr_subh_update_time",
            "hrrr_0_18_update_time",
            "nbm_update_time",
            "nbm_fire_update_time",
            "hrrr_18_48_update_time",
            "gfs_update_time",
            "gefs_update_time",
        ]:
            try:
                flags = self._weather_coordinator.data.flags()
                model_time_string = flags.sourceTimes[self.entity_description.key]
                native_val = datetime.datetime.strptime(
                    model_time_string[0:-1], "%Y-%m-%d %H"
                ).replace(tzinfo=datetime.UTC)
            except KeyError:
                native_val = None

        elif self.type == "minutely_summary":
            native_val = getattr(
                self._weather_coordinator.data.minutely(), "summary", ""
            )
            self._icon = getattr(self._weather_coordinator.data.minutely(), "icon", "")
        elif self.type == "hourly_summary":
            native_val = getattr(self._weather_coordinator.data.hourly(), "summary", "")
            self._icon = getattr(self._weather_coordinator.data.hourly(), "icon", "")

        elif self.forecast_hour is not None:
            hourly = self._weather_coordinator.data.hourly()
            if hasattr(hourly, "data"):
                native_val = self.get_state(hourly.data[self.forecast_hour].d)
            else:
                native_val = 0

        elif self.type == "daily_summary":
            native_val = getattr(self._weather_coordinator.data.daily(), "summary", "")
            self._icon = getattr(self._weather_coordinator.data.daily(), "icon", "")

        elif self.forecast_day is not None:
            daily = self._weather_coordinator.data.daily()
            if hasattr(daily, "data"):
                native_val = self.get_state(daily.data[self.forecast_day].d)
            else:
                native_val = 0
        else:
            currently = self._weather_coordinator.data.currently()
            native_val = self.get_state(currently.d)

        # self._state = native_val

        return native_val

    def get_state(self, data):
        """Return a new state based on the type.

        If the sensor type is unknown, the current state is returned.
        """

        if self.type == "fire_risk_level":
            if self.forecast_hour is not None:
                state = data.get("fireIndex")
            elif self.forecast_day is not None:
                state = data.get("fireIndexMax")
            else:
                state = data.get("fireIndex")
        else:
            lookup_type = convert_to_camel(self.type)
            state = data.get(lookup_type)

            # If the sensor is numeric and the data is -999 set return None instead of -999
            if isinstance(state, (int, float)) and state == -999:
                return None

        if state is None:
            return state

        if "summary" in self.type:
            self._icon = getattr(data, "icon", "")

        # If output rounding is requested, round to nearest integer
        if self.output_round == "Yes":
            rounding_val = 0
            rounding_precip = 2
        else:
            rounding_val = 2
            rounding_precip = 4

        # Some state data needs to be rounded to whole values or converted to
        # percentages
        if self.type in ["precip_probability", "cloud_cover", "humidity"]:
            state = int(state * 100)

        # Convert unix times to datetimes times
        if self.type in [
            "temperature_high_time",
            "temperature_min_time",
            "apparent_temperature_high_time",
            "apparent_temperature_low_time",
            "sunrise_time",
            "sunset_time",
            "time",
        ]:
            out_state = datetime.datetime.fromtimestamp(state, datetime.UTC)

        elif self.type == "fire_risk_level":
            out_state = fire_index(state)
        elif self.type in [
            "dew_point",
            "temperature",
            "apparent_temperature",
            "temperature_low",
            "apparent_temperature_low",
            "temperature_min",
            "apparent_temperature_min",
            "temperature_high",
            "apparent_temperature_high",
            "temperature_max",
            "apparent_temperature_max",
            "pressure",
            "ozone",
            "fire_index",
            "fire_index_max",
            "uv_index",
            "air_quality_index",
            "wind_speed",
            "wind_gust",
            "visibility",
            "nearest_storm_distance",
            "smoke",
            "smoke_max",
            "solar",
            "solar_max",
        ]:
            if rounding_val == 0:
                out_state = int(round(state, rounding_val))
            else:
                out_state = round(state, rounding_val)

        elif self.type in [
            "precip_accumulation",
            "liquid_accumulation",
            "snow_accumulation",
            "ice_accumulation",
            "precip_intensity",
            "precip_intensity_max",
            "current_day_liquid",
            "current_day_snow",
            "current_day_ice",
            "rain_intensity",
            "rain_intensity_max",
            "snow_intensity",
            "snow_intensity_max",
            "ice_intensity",
            "ice_intensity_max",
        ]:
            # Convert snow intensity from cm/h to mm/h for non-US units
            if (
                self.type in ["snow_intensity", "snow_intensity_max"]
                and self.unit_system != "us"
            ):
                state = state * 10
            out_state = round(state, rounding_precip)

        else:
            out_state = state

        return out_state

    async def async_added_to_hass(self) -> None:
        """Connect to dispatcher listening for entity data notifications."""
        self.async_on_remove(
            self._weather_coordinator.async_add_listener(self.async_write_ha_state)
        )

    # async def async_update(self) -> None:
    #    """Get the latest data from PW and updates the states."""
    #    await self._weather_coordinator.async_request_refresh()


def convert_to_camel(data):
    """Convert snake case (foo_bar_bat) to camel case (fooBarBat).

    This is not pythonic, but needed for certain situations.
    """
    components = data.split("_")
    capital_components = "".join(x.title() for x in components[1:])
    return f"{components[0]}{capital_components}"


def fire_index(fire_index):
    """Convert numeric fire index to a textual value."""

    if fire_index == -999:
        out_state = "N/A"
    elif fire_index >= 30:
        out_state = "Extreme"
    elif fire_index >= 20:
        out_state = "Very High"
    elif fire_index >= 10:
        out_state = "High"
    elif fire_index >= 5:
        out_state = "Moderate"
    else:
        out_state = "Low"

    return out_state
