"""Philips Hue device provider — entertainment streaming to Hue lights."""

import asyncio
from typing import List, Tuple

from wled_controller.core.devices.led_client import (
    DeviceHealth,
    DiscoveredDevice,
    LEDClient,
    LEDDeviceProvider,
)
from wled_controller.core.devices.hue_client import HueClient
from wled_controller.utils import get_logger

logger = get_logger(__name__)


class HueDeviceProvider(LEDDeviceProvider):
    """Provider for Philips Hue Entertainment API streaming.

    URL format: hue://<bridge-ip>
    Each device = one entertainment group on the bridge.
    LED count = number of lights in the entertainment group.
    """

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

    @property
    def capabilities(self) -> set:
        return {
            "manual_led_count",
            "brightness_control",
            "power_control",
            "health_check",
            "static_color",
        }

    def create_client(self, url: str, **kwargs) -> LEDClient:
        return HueClient(
            url,
            led_count=kwargs.get("led_count", 0),
            hue_username=kwargs.get("hue_username", ""),
            hue_client_key=kwargs.get("hue_client_key", ""),
            hue_entertainment_group_id=kwargs.get("hue_entertainment_group_id", ""),
        )

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

    async def validate_device(self, url: str) -> dict:
        """Validate Hue bridge is reachable. LED count is manual (depends on entertainment group)."""
        bridge_ip = url.replace("hue://", "").rstrip("/")
        try:
            import httpx

            async with httpx.AsyncClient(verify=False, timeout=5.0) as client:
                resp = await client.get(f"https://{bridge_ip}/api/0/config")
                if resp.status_code == 200:
                    data = resp.json()
                    if "bridgeid" in data or "name" in data:
                        return {}
            raise ValueError(f"Device at {bridge_ip} does not appear to be a Hue bridge")
        except ValueError:
            raise
        except Exception as e:
            raise ValueError(f"Cannot reach Hue bridge at {bridge_ip}: {e}")

    async def discover(self, timeout: float = 3.0) -> List[DiscoveredDevice]:
        """Discover Hue bridges via mDNS."""
        results = []
        try:
            from zeroconf import ServiceBrowser, Zeroconf

            found = []

            class Listener:
                def add_service(self, zc, type_, name):
                    info = zc.get_service_info(type_, name)
                    if info:
                        found.append(info)

                def remove_service(self, zc, type_, name):
                    pass

                def update_service(self, zc, type_, name):
                    pass

            zc = Zeroconf()
            try:
                ServiceBrowser(zc, "_hue._tcp.local.", Listener())
                await asyncio.sleep(min(timeout, 3.0))

                for info in found:
                    addresses = info.parsed_addresses()
                    if not addresses:
                        continue
                    ip = addresses[0]
                    name = info.server.rstrip(".")
                    results.append(
                        DiscoveredDevice(
                            name=f"Hue Bridge ({name})",
                            url=f"hue://{ip}",
                            device_type="hue",
                            ip=ip,
                            mac="",
                            led_count=None,
                            version=None,
                        )
                    )
            finally:
                zc.close()
        except ImportError:
            logger.debug("zeroconf not available for Hue discovery")
        return results

    async def get_brightness(self, url: str) -> int:
        """Get bridge group brightness (not per-light)."""
        raise NotImplementedError

    async def set_brightness(self, url: str, brightness: int) -> None:
        """Software brightness — handled at send time."""
        raise NotImplementedError

    async def get_power(self, url: str, **kwargs) -> bool:
        return True

    async def set_power(self, url: str, on: bool, **kwargs) -> None:
        """Turn all lights in group on/off via REST API."""
        bridge_ip = url.replace("hue://", "").rstrip("/")
        hue_username = kwargs.get("hue_username", "")
        group_id = kwargs.get("hue_entertainment_group_id", "")
        if not hue_username or not group_id:
            return
        try:
            import httpx

            api_url = f"https://{bridge_ip}/clip/v2/resource/grouped_light"
            headers = {"hue-application-key": hue_username}
            async with httpx.AsyncClient(verify=False, timeout=5.0) as client:
                resp = await client.get(api_url, headers=headers)
                if resp.status_code == 200:
                    # Find the grouped_light for our entertainment config
                    for item in resp.json().get("data", []):
                        await client.put(
                            f"{api_url}/{item['id']}",
                            json={"on": {"on": on}},
                            headers=headers,
                        )
        except Exception as e:
            logger.error("Failed to set Hue power: %s", e)

    async def set_color(self, url: str, color: Tuple[int, int, int], **kwargs) -> None:
        """Set all lights to a solid color via REST API."""
        bridge_ip = url.replace("hue://", "").rstrip("/")
        hue_username = kwargs.get("hue_username", "")
        if not hue_username:
            return
        try:
            import httpx

            headers = {"hue-application-key": hue_username}
            # Convert RGB to CIE xy for Hue API
            r, g, b = [c / 255.0 for c in color]
            # sRGB to linear
            r = r / 12.92 if r <= 0.04045 else ((r + 0.055) / 1.055) ** 2.4
            g = g / 12.92 if g <= 0.04045 else ((g + 0.055) / 1.055) ** 2.4
            b = b / 12.92 if b <= 0.04045 else ((b + 0.055) / 1.055) ** 2.4
            X = r * 0.4124 + g * 0.3576 + b * 0.1805
            Y = r * 0.2126 + g * 0.7152 + b * 0.0722
            Z = r * 0.0193 + g * 0.1192 + b * 0.9505
            total = X + Y + Z
            if total > 0:
                x = X / total
                y = Y / total
            else:
                x, y = 0.3127, 0.3290  # D65 white point

            api_url = f"https://{bridge_ip}/clip/v2/resource/light"
            async with httpx.AsyncClient(verify=False, timeout=5.0) as client:
                resp = await client.get(api_url, headers=headers)
                if resp.status_code == 200:
                    for light in resp.json().get("data", []):
                        await client.put(
                            f"{api_url}/{light['id']}",
                            json={
                                "on": {"on": True},
                                "color": {"xy": {"x": round(x, 4), "y": round(y, 4)}},
                            },
                            headers=headers,
                        )
        except Exception as e:
            logger.error("Failed to set Hue color: %s", e)
