"""The LED Screen Controller integration."""

from __future__ import annotations

import logging
from datetime import timedelta

import voluptuous as vol

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.aiohttp_client import async_get_clientsession

from .const import (
    DOMAIN,
    CONF_SERVER_NAME,
    CONF_SERVER_URL,
    CONF_API_KEY,
    DEFAULT_SCAN_INTERVAL,
    TARGET_TYPE_HA_LIGHT,
    DATA_COORDINATOR,
    DATA_EVENT_LISTENER,
)
from .coordinator import WLEDScreenControllerCoordinator
from .event_listener import EventStreamListener

_LOGGER = logging.getLogger(__name__)

PLATFORMS: list[Platform] = [
    Platform.BUTTON,
    Platform.LIGHT,
    Platform.SWITCH,
    Platform.SENSOR,
    Platform.NUMBER,
    Platform.SELECT,
]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up LED Screen Controller from a config entry."""
    server_name = entry.data.get(CONF_SERVER_NAME, "LED Screen Controller")
    server_url = entry.data[CONF_SERVER_URL]
    api_key = entry.data[CONF_API_KEY]

    session = async_get_clientsession(hass)
    coordinator = WLEDScreenControllerCoordinator(
        hass,
        session,
        server_url,
        api_key,
        update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL),
    )

    await coordinator.async_config_entry_first_refresh()

    event_listener = EventStreamListener(hass, server_url, api_key, coordinator)
    await event_listener.start()

    # Create device entries for each target and remove stale ones
    device_registry = dr.async_get(hass)
    current_identifiers: set[tuple[str, str]] = set()
    if coordinator.data and "targets" in coordinator.data:
        for target_id, target_data in coordinator.data["targets"].items():
            info = target_data["info"]
            target_type = info.get("target_type", "led")
            if target_type == TARGET_TYPE_HA_LIGHT:
                model = "HA Light Target"
            else:
                model = "LED Target"
            device_registry.async_get_or_create(
                config_entry_id=entry.entry_id,
                identifiers={(DOMAIN, target_id)},
                name=info.get("name", target_id),
                manufacturer=server_name,
                model=model,
                configuration_url=server_url,
            )
            current_identifiers.add((DOMAIN, target_id))

    # Create a single "Scenes" device for scene preset buttons
    scenes_identifier = (DOMAIN, f"{entry.entry_id}_scenes")
    scene_presets = coordinator.data.get("scene_presets", []) if coordinator.data else []
    if scene_presets:
        device_registry.async_get_or_create(
            config_entry_id=entry.entry_id,
            identifiers={scenes_identifier},
            name="Scenes",
            manufacturer=server_name,
            model="Scene Presets",
            configuration_url=server_url,
        )
        current_identifiers.add(scenes_identifier)

    # Remove devices for targets that no longer exist
    for device_entry in dr.async_entries_for_config_entry(device_registry, entry.entry_id):
        if not device_entry.identifiers & current_identifiers:
            _LOGGER.info("Removing stale device: %s", device_entry.name)
            device_registry.async_remove_device(device_entry.id)

    # Store data
    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.entry_id] = {
        DATA_COORDINATOR: coordinator,
        DATA_EVENT_LISTENER: event_listener,
    }

    # Track target and scene IDs to detect changes
    known_target_ids = set(coordinator.data.get("targets", {}).keys() if coordinator.data else [])
    known_scene_ids = set(
        p["id"] for p in (coordinator.data.get("scene_presets", []) if coordinator.data else [])
    )

    def _on_coordinator_update() -> None:
        """Detect target/scene list changes and trigger reload."""
        nonlocal known_target_ids, known_scene_ids

        if not coordinator.data:
            return

        targets = coordinator.data.get("targets", {})

        # Reload if target or scene list changed
        current_ids = set(targets.keys())
        current_scene_ids = set(p["id"] for p in coordinator.data.get("scene_presets", []))
        if current_ids != known_target_ids or current_scene_ids != known_scene_ids:
            known_target_ids = current_ids
            known_scene_ids = current_scene_ids
            _LOGGER.info("Target or scene list changed, reloading integration")
            hass.async_create_task(hass.config_entries.async_reload(entry.entry_id))

    coordinator.async_add_listener(_on_coordinator_update)

    # Register set_leds service (once across all entries)
    async def handle_set_leds(call) -> None:
        """Handle the set_leds service call."""
        source_id = call.data["source_id"]
        segments = call.data["segments"]
        # Route to the coordinator that owns this source
        for entry_data in hass.data[DOMAIN].values():
            coord = entry_data.get(DATA_COORDINATOR)
            if not coord or not coord.data:
                continue
            source_ids = {s["id"] for s in coord.data.get("css_sources", [])}
            if source_id in source_ids:
                await coord.push_segments(source_id, segments)
                return
        _LOGGER.error("No server found with source_id %s", source_id)

    if not hass.services.has_service(DOMAIN, "set_leds"):
        hass.services.async_register(
            DOMAIN,
            "set_leds",
            handle_set_leds,
            schema=vol.Schema(
                {
                    vol.Required("source_id"): str,
                    vol.Required("segments"): list,
                }
            ),
        )

    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

    return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Unload a config entry."""
    entry_data = hass.data[DOMAIN][entry.entry_id]
    await entry_data[DATA_EVENT_LISTENER].shutdown()

    unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

    if unload_ok:
        hass.data[DOMAIN].pop(entry.entry_id)
        # Unregister service if no entries remain
        if not hass.data[DOMAIN]:
            hass.services.async_remove(DOMAIN, "set_leds")

    return unload_ok
