"""Demo platform for the geolocation component."""

from datetime import timedelta
import logging
from math import cos, pi, radians, sin
import random
from typing import override

from homeassistant.components.geo_location import GeolocationEvent
from homeassistant.const import UnitOfLength
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import track_time_interval
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

_LOGGER = logging.getLogger(__name__)

AVG_KM_PER_DEGREE = 111.0
DEFAULT_UPDATE_INTERVAL = timedelta(minutes=1)
MAX_RADIUS_IN_KM = 50
NUMBER_OF_DEMO_DEVICES = 2

EVENTS = [
    {"name": "Bushfire", "icon": "mdi:fire"},
    {"name": "Hazard Reduction", "icon": "mdi:alarm-light"},
    {"name": "Grass Fire", "icon": "mdi:fire"},
    {"name": "Burn off", "icon": "mdi:fire"},
    {"name": "Structure Fire", "icon": "mdi:wall-fire"},
    {"name": "Fire Alarm", "icon": "mdi:fire-truck"},
    {"name": "Thunderstorm", "icon": "mdi:weather-lightning-rainy"},
    {"name": "Tornado", "icon": "mdi:weather-tornado"},
    {"name": "Cyclone", "icon": "mdi:weather-tornado"},
    {"name": "Waterspout", "icon": "mdi:weather-tornado"},
    {"name": "Dust Storm", "icon": "mdi:weather-dust"},
    {"name": "Blizzard", "icon": "mdi:weather-snowy-heavy"},
    {"name": "Ice Storm", "icon": "mdi:snowflake-alert"},
    {"name": "Earthquake", "icon": "mdi:earth"},
    {"name": "Tsunami", "icon": "mdi:waves-arrow-right"},
]

SOURCE = "demo"


def setup_platform(
    hass: HomeAssistant,
    config: ConfigType,
    add_entities: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType | None = None,
) -> None:
    """Set up the Demo geolocations."""
    DemoManager(hass, add_entities)


class DemoManager:
    """Device manager for demo geolocation events."""

    def __init__(self, hass: HomeAssistant, add_entities: AddEntitiesCallback) -> None:
        """Initialise the demo geolocation event manager."""
        self._hass = hass
        self._add_entities = add_entities
        self._managed_devices: list[DemoGeolocationEvent] = []
        self._update(count=NUMBER_OF_DEMO_DEVICES)
        self._init_regular_updates()

    def _generate_random_event(self) -> DemoGeolocationEvent:
        """Generate a random event in vicinity of this HA instance."""
        home_latitude = self._hass.config.latitude
        home_longitude = self._hass.config.longitude

        # Approx. 111km per degree (north-south).
        radius_in_degrees = random.random() * MAX_RADIUS_IN_KM / AVG_KM_PER_DEGREE
        radius_in_km = radius_in_degrees * AVG_KM_PER_DEGREE
        angle = random.random() * 2 * pi
        # Compute coordinates based on radius and angle. Adjust longitude value
        # based on HA's latitude.
        latitude = home_latitude + radius_in_degrees * sin(angle)
        longitude = home_longitude + radius_in_degrees * cos(angle) / cos(
            radians(home_latitude)
        )

        event = random.choice(EVENTS)
        return DemoGeolocationEvent(
            event["name"],
            event["icon"],
            radius_in_km,
            latitude,
            longitude,
            UnitOfLength.KILOMETERS,
        )

    def _init_regular_updates(self) -> None:
        """Schedule regular updates based on configured time interval."""
        track_time_interval(
            self._hass,
            lambda now: self._update(),
            DEFAULT_UPDATE_INTERVAL,
            cancel_on_shutdown=True,
        )

    def _update(self, count: int = 1) -> None:
        """Remove events and add new random events."""
        # Remove devices.
        for _ in range(1, count + 1):
            if self._managed_devices:
                device = random.choice(self._managed_devices)
                if device:
                    _LOGGER.debug("Removing %s", device)
                    self._managed_devices.remove(device)
                    self._hass.add_job(device.async_remove())
        # Generate new devices from events.
        new_devices = []
        for _ in range(1, count + 1):
            new_device = self._generate_random_event()
            _LOGGER.debug("Adding %s", new_device)
            new_devices.append(new_device)
            self._managed_devices.append(new_device)
        self._add_entities(new_devices)


class DemoGeolocationEvent(GeolocationEvent):
    """Represents a demo geolocation event."""

    _attr_should_poll = False

    def __init__(
        self,
        name: str,
        icon: str,
        distance: float,
        latitude: float,
        longitude: float,
        unit_of_measurement: str,
    ) -> None:
        """Initialize entity with data provided."""
        self._attr_name = name
        self._distance = distance
        self._latitude = latitude
        self._longitude = longitude
        self._unit_of_measurement = unit_of_measurement
        self._attr_icon = icon

    @property
    @override
    def source(self) -> str:
        """Return source value of this external event."""
        return SOURCE

    @property
    @override
    def distance(self) -> float | None:
        """Return distance value of this external event."""
        return self._distance

    @property
    @override
    def latitude(self) -> float | None:
        """Return latitude value of this external event."""
        return self._latitude

    @property
    @override
    def longitude(self) -> float | None:
        """Return longitude value of this external event."""
        return self._longitude

    @property
    @override
    def unit_of_measurement(self) -> str:
        """Return the unit of measurement."""
        return self._unit_of_measurement
