"""DIO (Digital Output) converters — proto <-> domain."""

from __future__ import annotations

from radiens_core._generated import allegoserver_pb2
from radiens_core.models.dio import DigitalOutChannelRegister, DigitalOutRegister, DIOMode

# --- DIOMode ---

_DIO_MODE_TO_PROTO: dict[DIOMode, allegoserver_pb2.DIOMode.ValueType] = {
    DIOMode.MANUAL: allegoserver_pb2.manual,
    DIOMode.EVENTS: allegoserver_pb2.events,
    DIOMode.GATED: allegoserver_pb2.gated,
    DIOMode.PULSE: allegoserver_pb2.pulse,
}

_DIO_MODE_FROM_PROTO: dict[int, DIOMode] = {
    int(allegoserver_pb2.manual): DIOMode.MANUAL,
    int(allegoserver_pb2.events): DIOMode.EVENTS,
    int(allegoserver_pb2.gated): DIOMode.GATED,
    int(allegoserver_pb2.pulse): DIOMode.PULSE,
}


def dio_mode_to_proto(mode: DIOMode) -> allegoserver_pb2.DIOMode.ValueType:
    """Convert domain DIOMode to proto DIOMode."""
    return _DIO_MODE_TO_PROTO[mode]


def dio_mode_from_proto(pb: int) -> DIOMode:
    """Convert proto DIOMode int to domain DIOMode."""
    return _DIO_MODE_FROM_PROTO[pb]


# --- Requests ---


def set_dio_events_to_proto(
    chan_idx: int,
    threshold: float,
    polarity: bool,
) -> allegoserver_pb2.DIOModeEventsRequest:
    """Convert DIO events parameters to ``DIOModeEventsRequest`` proto."""
    return allegoserver_pb2.DIOModeEventsRequest(
        chanIdx=chan_idx,
        eventThreshold=threshold,
        eventPolarity=polarity,
    )


def set_dio_manual_to_proto(
    chan_idx: int,
    state: bool,
) -> allegoserver_pb2.DIOModeManualRequest:
    """Convert DIO manual parameters to ``DIOModeManualRequest`` proto."""
    return allegoserver_pb2.DIOModeManualRequest(
        chanIdx=chan_idx,
        state=state,
    )


def set_dio_gated_to_proto(
    polarity: bool,
) -> allegoserver_pb2.DIOModeGatedRequest:
    """Convert DIO gated parameters to ``DIOModeGatedRequest`` proto."""
    return allegoserver_pb2.DIOModeGatedRequest(
        gatedPolarity=polarity,
    )


def set_dio_pulse_to_proto(
    interval_sec: float,
    duration_sec: float,
    chan_idx: int = -1,
) -> allegoserver_pb2.DIOModePulseRequest:
    """Convert DIO pulse parameters to ``DIOModePulseRequest`` proto."""
    return allegoserver_pb2.DIOModePulseRequest(
        reqIntervalSec=interval_sec,
        reqDurationSec=duration_sec,
        reqNtvChanIdx=chan_idx,
    )


# --- Register ---


def digital_out_channel_register_from_proto(
    proto: allegoserver_pb2.DigitalOutChannelRegister,
) -> DigitalOutChannelRegister:
    """Convert ``DigitalOutChannelRegister`` proto to domain model."""
    return DigitalOutChannelRegister(
        manual_state=proto.manualState,
        event_threshold=proto.eventThreshold,
        event_polarity=proto.eventPolarity,
        ntv_chan_idx=proto.ntvChanIdx,
        pulse_interval_sec=proto.pulseIntervalSec,
        pulse_duration_sec=proto.pulseDurationSec,
    )


def digital_out_register_from_proto(
    proto: allegoserver_pb2.DigitalOutRegister,
) -> DigitalOutRegister:
    """Convert ``DigitalOutRegister`` proto to domain model."""
    return DigitalOutRegister(
        mode=dio_mode_from_proto(proto.mode),
        dout_chan_registers=[digital_out_channel_register_from_proto(c) for c in proto.doutChanRegisters],
        gated_polarity=proto.gatedPolarity,
        req_pulse_interval_sec=proto.reqPulseIntervalSec,
        req_pulse_duration_sec=proto.reqPulseDurationSec,
        req_pulse_ntv_chan_idx=proto.reqPulseNtvChanIdx,
    )
