"""DDP device provider — standalone UDP target for any DDP-speaking receiver."""

from __future__ import annotations

from typing import TYPE_CHECKING, List

from ledgrab.core.devices.ddp_led_client import DDPLEDClient, parse_ddp_url
from ledgrab.utils.net_classify import validate_lan_host
from ledgrab.core.devices.led_client import (
    DeviceHealth,
    DiscoveredDevice,
    LEDClient,
    LEDDeviceProvider,
    ProviderDeps,
)
from ledgrab.utils import get_logger

if TYPE_CHECKING:
    from ledgrab.core.devices.device_config import DDPConfig

logger = get_logger(__name__)


class DDPDeviceProvider(LEDDeviceProvider):
    """Provider for generic DDP receivers (Pixelblaze, ESPixelStick, Falcon, …).

    DDP has no native discovery protocol — callers must supply a manual IP/host.
    LED count is also user-supplied since DDP receivers don't expose a metadata
    channel back to the sender.
    """

    @property
    def device_type(self) -> str:
        return "ddp"

    @property
    def capabilities(self) -> set:
        # No power_control / brightness_control: DDP receivers don't define a
        # standard reply channel, so we cannot read back state. Software
        # brightness is still applied client-side before the frame is sent.
        return {"manual_led_count", "health_check"}

    def create_client(self, config: "DDPConfig", *, deps: ProviderDeps) -> LEDClient:
        return DDPLEDClient(
            config.device_url,
            led_count=config.led_count,
            rgbw=config.rgbw,
            port=config.ddp_port or None,
            destination_id=config.ddp_destination_id,
            color_order=config.ddp_color_order,
        )

    async def check_health(self, url: str, http_client, prev_health=None) -> DeviceHealth:
        return await DDPLEDClient.check_health(url, http_client, prev_health)

    async def validate_device(self, url: str) -> dict:
        """Validate URL parses cleanly. DDP receivers don't report LED count."""
        try:
            host, port = parse_ddp_url(url)
        except ValueError as exc:
            raise ValueError(f"Invalid DDP URL: {exc}") from exc
        validate_lan_host(host)
        logger.info("DDP device URL validated: host=%s port=%d", host, port)
        return {}

    async def discover(self, timeout: float = 3.0) -> List[DiscoveredDevice]:
        """DDP has no native discovery — returns empty list."""
        return []
