"""Utility functions for retrieving friendly monitor/display names."""

import ctypes
import sys
from typing import Dict

from wled_controller.utils import get_logger

logger = get_logger(__name__)


def get_monitor_names() -> Dict[int, str]:
    """Get friendly names for connected monitors.

    On Windows, enumerates display adapters and their monitors via
    ``EnumDisplayDevicesW`` (pure ctypes, no third-party dependencies).
    On other platforms, returns empty dict (will fall back to generic names).

    Returns:
        Dictionary mapping display indices to friendly names
    """
    if sys.platform != "win32":
        logger.debug("Monitor name detection only supported on Windows")
        return {}

    try:
        from ctypes import wintypes

        class DISPLAY_DEVICEW(ctypes.Structure):
            _fields_ = [
                ("cb", wintypes.DWORD),
                ("DeviceName", ctypes.c_wchar * 32),
                ("DeviceString", ctypes.c_wchar * 128),
                ("StateFlags", wintypes.DWORD),
                ("DeviceID", ctypes.c_wchar * 128),
                ("DeviceKey", ctypes.c_wchar * 128),
            ]

        user32 = ctypes.windll.user32

        DISPLAY_DEVICE_ACTIVE = 0x00000001
        DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = 0x00000002

        monitor_names: Dict[int, str] = {}
        monitor_idx = 0

        # Enumerate display adapters (GPUs / virtual outputs)
        adapter_idx = 0
        while adapter_idx < 16:  # safety limit
            adapter = DISPLAY_DEVICEW()
            adapter.cb = ctypes.sizeof(DISPLAY_DEVICEW)

            if not user32.EnumDisplayDevicesW(None, adapter_idx, ctypes.byref(adapter), 0):
                break
            adapter_idx += 1

            # Skip adapters not attached to the desktop
            if not (adapter.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP):
                continue

            # Enumerate monitors attached to this adapter
            child_idx = 0
            while child_idx < 16:  # safety limit
                monitor = DISPLAY_DEVICEW()
                monitor.cb = ctypes.sizeof(DISPLAY_DEVICEW)

                if not user32.EnumDisplayDevicesW(
                    adapter.DeviceName, child_idx, ctypes.byref(monitor), 0
                ):
                    break
                child_idx += 1

                if not (monitor.StateFlags & DISPLAY_DEVICE_ACTIVE):
                    continue

                # DeviceString contains the friendly name (e.g. "DELL U2718Q")
                friendly_name = monitor.DeviceString.strip()
                if not friendly_name:
                    friendly_name = f"Display {monitor_idx}"

                monitor_names[monitor_idx] = friendly_name
                logger.debug(f"Monitor {monitor_idx}: {friendly_name}")
                monitor_idx += 1

        return monitor_names

    except Exception as e:
        logger.debug(f"Failed to retrieve monitor names via EnumDisplayDevices: {e}")
        return {}


def get_monitor_name(index: int) -> str:
    """Get friendly name for a specific monitor.

    Args:
        index: Monitor index (0-based)

    Returns:
        Friendly monitor name or generic fallback
    """
    monitor_names = get_monitor_names()
    return monitor_names.get(index, f"Display {index}")


def get_monitor_refresh_rates() -> Dict[int, int]:
    """Get refresh rates (in Hz) for connected monitors.

    On Windows, attempts to retrieve refresh rates from display settings.
    On other platforms, returns empty dict (will use default 60Hz).

    Returns:
        Dictionary mapping display indices to refresh rates in Hz
    """
    if sys.platform != "win32":
        logger.debug("Refresh rate detection only supported on Windows")
        return {}

    try:
        import ctypes
        from ctypes import wintypes

        # Define Windows structures
        class DEVMODE(ctypes.Structure):
            _fields_ = [
                ('dmDeviceName', ctypes.c_wchar * 32),
                ('dmSpecVersion', wintypes.WORD),
                ('dmDriverVersion', wintypes.WORD),
                ('dmSize', wintypes.WORD),
                ('dmDriverExtra', wintypes.WORD),
                ('dmFields', wintypes.DWORD),
                ('dmPositionX', wintypes.LONG),
                ('dmPositionY', wintypes.LONG),
                ('dmDisplayOrientation', wintypes.DWORD),
                ('dmDisplayFixedOutput', wintypes.DWORD),
                ('dmColor', wintypes.SHORT),
                ('dmDuplex', wintypes.SHORT),
                ('dmYResolution', wintypes.SHORT),
                ('dmTTOption', wintypes.SHORT),
                ('dmCollate', wintypes.SHORT),
                ('dmFormName', ctypes.c_wchar * 32),
                ('dmLogPixels', wintypes.WORD),
                ('dmBitsPerPel', wintypes.DWORD),
                ('dmPelsWidth', wintypes.DWORD),
                ('dmPelsHeight', wintypes.DWORD),
                ('dmDisplayFlags', wintypes.DWORD),
                ('dmDisplayFrequency', wintypes.DWORD),
            ]

        user32 = ctypes.windll.user32
        refresh_rates = {}

        # Enumerate all display devices
        idx = 0
        while True:
            ctypes.create_unicode_buffer(32)
            if not user32.EnumDisplayDevicesW(None, idx, None, 0):
                # Try getting display settings by index
                devmode = DEVMODE()
                devmode.dmSize = ctypes.sizeof(DEVMODE)

                if user32.EnumDisplaySettingsW(None, -1, ctypes.byref(devmode)):  # ENUM_CURRENT_SETTINGS = -1
                    refresh_rate = devmode.dmDisplayFrequency
                    if refresh_rate > 0:
                        refresh_rates[idx] = refresh_rate
                        logger.debug(f"Display {idx}: {refresh_rate}Hz")

                idx += 1
                if idx > 10:  # Safety limit
                    break
            else:
                break

        # If no refresh rates found, try alternative method
        if not refresh_rates:
            devmode = DEVMODE()
            devmode.dmSize = ctypes.sizeof(DEVMODE)

            for monitor_idx in range(4):  # Check up to 4 monitors
                if user32.EnumDisplaySettingsW(None, -1, ctypes.byref(devmode)):
                    refresh_rate = devmode.dmDisplayFrequency
                    if refresh_rate > 0:
                        refresh_rates[monitor_idx] = refresh_rate
                        logger.debug(f"Monitor {monitor_idx}: {refresh_rate}Hz")

        return refresh_rates

    except Exception as e:
        logger.debug(f"Failed to retrieve monitor refresh rates: {e}")
        return {}
