"""
USB device whitelist enforcement (Linux only).

Monitors USB events via pyudev. On unrecognized device connection,
triggers a configurable callback (default: log warning).
"""

from __future__ import annotations

import json
import logging
from collections.abc import Callable
from pathlib import Path
from typing import Any

import soosef.paths as _paths

logger = logging.getLogger(__name__)

try:
    import pyudev

    HAS_PYUDEV = True
except ImportError:
    HAS_PYUDEV = False


def load_whitelist(path: Path | None = None) -> set[str]:
    """Load USB whitelist as set of 'vendor_id:product_id' strings."""
    wl_path = path or _paths.USB_WHITELIST
    if wl_path.exists():
        with open(wl_path) as f:
            data = json.load(f)
        return set(data.get("allowed", []))
    return set()


def save_whitelist(devices: set[str], path: Path | None = None) -> None:
    """Save USB whitelist."""
    wl_path = path or _paths.USB_WHITELIST
    wl_path.parent.mkdir(parents=True, exist_ok=True)
    with open(wl_path, "w") as f:
        json.dump({"allowed": sorted(devices)}, f, indent=2)


class USBMonitor:
    """Watch for USB device connections and check against whitelist."""

    def __init__(self, on_violation: Callable | None = None, whitelist_path: Path | None = None):
        if not HAS_PYUDEV:
            raise RuntimeError("pyudev not available — USB monitoring requires Linux + pyudev")

        self.whitelist = load_whitelist(whitelist_path)
        self.on_violation = on_violation or self._default_violation
        self._observer: Any = None

    def start(self) -> None:
        """Start monitoring USB events in a background thread."""
        context = pyudev.Context()
        monitor = pyudev.Monitor.from_netlink(context)
        monitor.filter_by(subsystem="usb")

        self._observer = pyudev.MonitorObserver(monitor, self._handle_event)
        self._observer.start()
        logger.info("USB monitoring started (whitelist: %d devices)", len(self.whitelist))

    def stop(self) -> None:
        """Stop monitoring."""
        if self._observer:
            self._observer.stop()
            self._observer = None

    def _handle_event(self, action: str, device: pyudev.Device) -> None:
        if action != "add":
            return

        vid = device.get("ID_VENDOR_ID", "")
        pid = device.get("ID_MODEL_ID", "")
        if not vid or not pid:
            return

        device_id = f"{vid}:{pid}"
        if device_id not in self.whitelist:
            vendor = device.get("ID_VENDOR", "unknown")
            model = device.get("ID_MODEL", "unknown")
            logger.warning("USB VIOLATION: %s (%s %s)", device_id, vendor, model)
            self.on_violation(device_id, vendor, model)

    @staticmethod
    def _default_violation(device_id: str, vendor: str, model: str) -> None:
        logger.warning("Unrecognized USB device: %s (%s %s)", device_id, vendor, model)
