"""
Driver registry — turn a catalog slug into a ready-to-record Source.

    from biosync import drivers
    drivers.available()                     # list every supported device slug
    src = drivers.make("enobio32")          # an LSL device (vendor app emits LSL)
    src = drivers.make("openbci_cyton", serial_port="/dev/ttyUSB0")   # a board
    src = drivers.make("tobii_pro")         # a vendor-SDK driver
    src.start()                             # publishes an LSL stream the recorder grabs

This is the layer that makes "any hardware iMotions sells can be bought and used":
every device in HARDWARE.md has a catalog entry, and `make()` routes it to the
right ingestion path automatically.
"""

from __future__ import annotations

import importlib

from .catalog import DEVICES, Device, by_modality, by_tier
from ..core.source import Source


def available(modality: str | None = None) -> list[str]:
    """All device slugs, optionally filtered by modality."""
    return sorted(d.slug for d in DEVICES.values()
                  if modality is None or d.modality == modality)


def describe(slug: str) -> Device:
    return DEVICES[slug]


def make(slug: str, **kwargs) -> Source:
    """Construct the Source for a catalog device. kwargs pass through to the driver
    (e.g. serial_port=, ip_address=, camera=, resolve_timeout=)."""
    if slug not in DEVICES:
        raise KeyError(f"unknown device {slug!r}; see drivers.available()")
    dev = DEVICES[slug]
    return _BUILDERS[dev.tier](dev, **kwargs)


# --- per-tier builders ----------------------------------------------------
def _build_lsl(dev: Device, **kw):
    from ..sources.lsl import LSLSource
    sel = {"stype": dev.lsl_type} if dev.lsl_type else {"name": dev.lsl_name}
    return LSLSource(out_name=dev.stype or dev.modality.upper(),
                     out_stype=dev.stype, out_channels=list(dev.channels) or None,
                     **sel, **kw)


def _build_brainflow(dev: Device, **kw):
    from ..sources.brainflow import BrainFlowSource
    from brainflow.board_shim import BoardIds
    board_id = getattr(BoardIds, dev.board)
    kind = {"eeg": "eeg", "ecg": "ecg", "eda": "eda", "emg": "emg"}.get(dev.modality, "eeg")
    return BrainFlowSource(board_id=board_id, name=dev.stype or "EEG",
                           stype=dev.stype or "EEG", channel_kind=kind,
                           labels=list(dev.channels) or None, **kw)


def _build_driver(dev: Device, **kw):
    """tier=sdk -> biosync.drivers.<mod>; tier=ml -> biosync.sources.<mod>."""
    mod_name, cls_name = dev.driver.split(":")
    base = "biosync.sources" if dev.tier == "ml" else "biosync.drivers"
    mod = importlib.import_module(f"{base}.{mod_name}")
    cls = getattr(mod, cls_name)
    return cls(device=dev, **kw)


_BUILDERS = {
    "lsl": _build_lsl,
    "brainflow": _build_brainflow,
    "sdk": _build_driver,
    "ml": _build_driver,
}
