"""SPI Direct device provider — Raspberry Pi GPIO/SPI direct LED strip control."""

import platform
from typing import List

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

logger = get_logger(__name__)


class SPIDeviceProvider(LEDDeviceProvider):
    """Provider for direct SPI/GPIO LED strip control on Raspberry Pi.

    URL formats:
        spi://gpio:18       — rpi_ws281x via GPIO pin 18 (PWM)
        spi://gpio:10       — rpi_ws281x via GPIO pin 10 (SPI MOSI)
        spi://spidev:0.0    — Raw SPI device /dev/spidev0.0

    Requires Linux (Raspberry Pi) and root privileges or appropriate permissions.
    """

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

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

    def create_client(self, url: str, **kwargs) -> LEDClient:
        return SPIClient(
            url,
            led_count=kwargs.get("led_count", 0),
            spi_speed_hz=kwargs.get("spi_speed_hz", 800000),
            spi_led_type=kwargs.get("spi_led_type", "WS2812B"),
        )

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

    async def validate_device(self, url: str) -> dict:
        """Validate SPI/GPIO is accessible. LED count is manual."""
        if platform.system() != "Linux":
            raise ValueError("SPI direct control is only available on Linux (Raspberry Pi)")

        from wled_controller.core.devices.spi_client import _parse_spi_url

        config = _parse_spi_url(url)
        if config["method"] == "spidev":
            import os

            dev_path = f"/dev/spidev{config['bus']}.{config['device']}"
            if not os.path.exists(dev_path):
                raise ValueError(f"SPI device {dev_path} not found. Enable SPI in raspi-config.")
        else:
            try:
                import rpi_ws281x  # noqa: F401
            except ImportError:
                raise ValueError("rpi_ws281x library required: pip install rpi_ws281x")

        return {}

    async def discover(self, timeout: float = 3.0) -> List[DiscoveredDevice]:
        """Discover available SPI devices on Raspberry Pi."""
        if platform.system() != "Linux":
            return []

        results = []

        # Check for SPI devices
        import os

        for bus in range(2):
            for device in range(2):
                path = f"/dev/spidev{bus}.{device}"
                if os.path.exists(path):
                    results.append(
                        DiscoveredDevice(
                            name=f"SPI Bus {bus} Device {device}",
                            url=f"spi://spidev:{bus}.{device}",
                            device_type="spi",
                            ip="",
                            mac="",
                            led_count=None,
                            version=None,
                        )
                    )

        # Check for GPIO availability
        try:
            import rpi_ws281x  # noqa: F401

            results.append(
                DiscoveredDevice(
                    name="GPIO 18 (PWM0)",
                    url="spi://gpio:18",
                    device_type="spi",
                    ip="",
                    mac="",
                    led_count=None,
                    version=None,
                )
            )
            results.append(
                DiscoveredDevice(
                    name="GPIO 10 (SPI MOSI)",
                    url="spi://gpio:10",
                    device_type="spi",
                    ip="",
                    mac="",
                    led_count=None,
                    version=None,
                )
            )
        except ImportError:
            pass

        return results

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

    async def set_power(self, url: str, on: bool, **kwargs) -> None:
        """Power off = send all-black frame."""
        pass  # Handled at target processor level
