"""Trigger control converters — domain ↔ proto."""

from __future__ import annotations

from typing import TYPE_CHECKING

from radiens_core._converters._common_enums import port_from_proto, port_to_proto
from radiens_core._generated import allegoserver_pb2
from radiens_core.models.triggers import (
    ManualStimTriggerRequest,
    ManualStimTriggerToggleRequest,
    SetTriggerStateRequest,
    TriggerChannel,
    TriggerState,
)

if TYPE_CHECKING:
    from radiens_core.models.ports import Port
    from radiens_core.models.stim import StimKeypressIndex

# --- TriggerChannel enum conversion ---

_TRIGGER_CHANNEL_TO_PROTO: dict[TriggerChannel, allegoserver_pb2.TriggerChannel.ValueType] = {
    TriggerChannel.T_DIN_0: allegoserver_pb2.T_DIN_0,
    TriggerChannel.T_DIN_1: allegoserver_pb2.T_DIN_1,
    TriggerChannel.T_DIN_2: allegoserver_pb2.T_DIN_2,
    TriggerChannel.T_DIN_3: allegoserver_pb2.T_DIN_3,
    TriggerChannel.T_DIN_4: allegoserver_pb2.T_DIN_4,
    TriggerChannel.T_DIN_5: allegoserver_pb2.T_DIN_5,
    TriggerChannel.T_DIN_6: allegoserver_pb2.T_DIN_6,
    TriggerChannel.T_DIN_7: allegoserver_pb2.T_DIN_7,
    TriggerChannel.T_DIN_8: allegoserver_pb2.T_DIN_8,
    TriggerChannel.T_DIN_9: allegoserver_pb2.T_DIN_9,
    TriggerChannel.T_DIN_10: allegoserver_pb2.T_DIN_10,
    TriggerChannel.T_DIN_11: allegoserver_pb2.T_DIN_11,
    TriggerChannel.T_DIN_12: allegoserver_pb2.T_DIN_12,
    TriggerChannel.T_DIN_13: allegoserver_pb2.T_DIN_13,
    TriggerChannel.T_DIN_14: allegoserver_pb2.T_DIN_14,
    TriggerChannel.T_DIN_15: allegoserver_pb2.T_DIN_15,
    TriggerChannel.T_DOUT_0: allegoserver_pb2.T_DOUT_0,
    TriggerChannel.T_DOUT_1: allegoserver_pb2.T_DOUT_1,
    TriggerChannel.T_DOUT_2: allegoserver_pb2.T_DOUT_2,
    TriggerChannel.T_DOUT_3: allegoserver_pb2.T_DOUT_3,
    TriggerChannel.T_DOUT_4: allegoserver_pb2.T_DOUT_4,
    TriggerChannel.T_DOUT_5: allegoserver_pb2.T_DOUT_5,
    TriggerChannel.T_DOUT_6: allegoserver_pb2.T_DOUT_6,
    TriggerChannel.T_DOUT_7: allegoserver_pb2.T_DOUT_7,
    TriggerChannel.T_DOUT_8: allegoserver_pb2.T_DOUT_8,
    TriggerChannel.T_DOUT_9: allegoserver_pb2.T_DOUT_9,
    TriggerChannel.T_DOUT_10: allegoserver_pb2.T_DOUT_10,
    TriggerChannel.T_DOUT_11: allegoserver_pb2.T_DOUT_11,
    TriggerChannel.T_DOUT_12: allegoserver_pb2.T_DOUT_12,
    TriggerChannel.T_DOUT_13: allegoserver_pb2.T_DOUT_13,
    TriggerChannel.T_DOUT_14: allegoserver_pb2.T_DOUT_14,
    TriggerChannel.T_DOUT_15: allegoserver_pb2.T_DOUT_15,
    TriggerChannel.T_NONE: allegoserver_pb2.T_NONE,
}

_TRIGGER_CHANNEL_FROM_PROTO: dict[int, TriggerChannel] = {
    int(allegoserver_pb2.T_DIN_0): TriggerChannel.T_DIN_0,
    int(allegoserver_pb2.T_DIN_1): TriggerChannel.T_DIN_1,
    int(allegoserver_pb2.T_DIN_2): TriggerChannel.T_DIN_2,
    int(allegoserver_pb2.T_DIN_3): TriggerChannel.T_DIN_3,
    int(allegoserver_pb2.T_DIN_4): TriggerChannel.T_DIN_4,
    int(allegoserver_pb2.T_DIN_5): TriggerChannel.T_DIN_5,
    int(allegoserver_pb2.T_DIN_6): TriggerChannel.T_DIN_6,
    int(allegoserver_pb2.T_DIN_7): TriggerChannel.T_DIN_7,
    int(allegoserver_pb2.T_DIN_8): TriggerChannel.T_DIN_8,
    int(allegoserver_pb2.T_DIN_9): TriggerChannel.T_DIN_9,
    int(allegoserver_pb2.T_DIN_10): TriggerChannel.T_DIN_10,
    int(allegoserver_pb2.T_DIN_11): TriggerChannel.T_DIN_11,
    int(allegoserver_pb2.T_DIN_12): TriggerChannel.T_DIN_12,
    int(allegoserver_pb2.T_DIN_13): TriggerChannel.T_DIN_13,
    int(allegoserver_pb2.T_DIN_14): TriggerChannel.T_DIN_14,
    int(allegoserver_pb2.T_DIN_15): TriggerChannel.T_DIN_15,
    int(allegoserver_pb2.T_DOUT_0): TriggerChannel.T_DOUT_0,
    int(allegoserver_pb2.T_DOUT_1): TriggerChannel.T_DOUT_1,
    int(allegoserver_pb2.T_DOUT_2): TriggerChannel.T_DOUT_2,
    int(allegoserver_pb2.T_DOUT_3): TriggerChannel.T_DOUT_3,
    int(allegoserver_pb2.T_DOUT_4): TriggerChannel.T_DOUT_4,
    int(allegoserver_pb2.T_DOUT_5): TriggerChannel.T_DOUT_5,
    int(allegoserver_pb2.T_DOUT_6): TriggerChannel.T_DOUT_6,
    int(allegoserver_pb2.T_DOUT_7): TriggerChannel.T_DOUT_7,
    int(allegoserver_pb2.T_DOUT_8): TriggerChannel.T_DOUT_8,
    int(allegoserver_pb2.T_DOUT_9): TriggerChannel.T_DOUT_9,
    int(allegoserver_pb2.T_DOUT_10): TriggerChannel.T_DOUT_10,
    int(allegoserver_pb2.T_DOUT_11): TriggerChannel.T_DOUT_11,
    int(allegoserver_pb2.T_DOUT_12): TriggerChannel.T_DOUT_12,
    int(allegoserver_pb2.T_DOUT_13): TriggerChannel.T_DOUT_13,
    int(allegoserver_pb2.T_DOUT_14): TriggerChannel.T_DOUT_14,
    int(allegoserver_pb2.T_DOUT_15): TriggerChannel.T_DOUT_15,
    int(allegoserver_pb2.T_NONE): TriggerChannel.T_NONE,
}


def trigger_channel_to_proto(tc: TriggerChannel) -> allegoserver_pb2.TriggerChannel.ValueType:
    """Convert domain TriggerChannel to proto TriggerChannel."""
    return _TRIGGER_CHANNEL_TO_PROTO[tc]


def trigger_channel_from_proto(pb: int) -> TriggerChannel:
    """Convert proto TriggerChannel int to domain TriggerChannel."""
    return _TRIGGER_CHANNEL_FROM_PROTO[pb]


def set_trigger_state_request_to_proto(
    request: SetTriggerStateRequest,
) -> allegoserver_pb2.SetTriggerRequest:
    """Convert ``SetTriggerStateRequest`` domain model → proto message."""
    return allegoserver_pb2.SetTriggerRequest(
        channel=trigger_channel_to_proto(request.channel),
        enabled=request.enabled,
        port=port_to_proto(request.port),
    )


def build_set_trigger_state_proto(
    channel: TriggerChannel,
    enabled: bool,
    port: Port,
) -> allegoserver_pb2.SetTriggerRequest:
    """Build a ``SetTriggerRequest`` proto from individual parameters."""
    return allegoserver_pb2.SetTriggerRequest(
        channel=trigger_channel_to_proto(channel),
        enabled=enabled,
        port=port_to_proto(port),
    )


def build_enable_trigger_proto(
    channel: TriggerChannel,
    port: Port | None,
) -> allegoserver_pb2.SetTriggerRequest:
    """Build a ``SetTriggerRequest`` proto to enable a trigger channel."""
    proto = allegoserver_pb2.SetTriggerRequest(
        channel=trigger_channel_to_proto(channel),
        enabled=True,
    )
    if port is not None:
        proto.port = port_to_proto(port)
    return proto


def build_disable_trigger_proto(
    channel: TriggerChannel,
    port: Port | None,
) -> allegoserver_pb2.SetTriggerRequest:
    """Build a ``SetTriggerRequest`` proto to disable a trigger channel."""
    proto = allegoserver_pb2.SetTriggerRequest(
        channel=trigger_channel_to_proto(channel),
        enabled=False,
    )
    if port is not None:
        proto.port = port_to_proto(port)
    return proto


def build_disable_all_triggers_proto() -> allegoserver_pb2.SetTriggerRequest:
    """Build a ``SetTriggerRequest`` proto to disable all trigger channels."""
    return allegoserver_pb2.SetTriggerRequest(
        channel=allegoserver_pb2.T_NONE,
        enabled=False,
    )


def trigger_state_from_proto(
    response: allegoserver_pb2.TriggerState,
) -> TriggerState:
    """Convert ``TriggerState`` proto response → domain model."""
    return TriggerState(
        enabled_channels=[trigger_channel_from_proto(channel) for channel in response.enabledChannels],
        ports=[port_from_proto(port) for port in response.ports],
    )


def manual_stim_trigger_request_to_proto(
    request: ManualStimTriggerRequest,
) -> allegoserver_pb2.ManualStimTriggerRequest:
    """Convert ``ManualStimTriggerRequest`` domain model → proto message."""
    # StimKeypressIndex is 1-indexed (1-8); proto expects 0-indexed (0-7)
    return allegoserver_pb2.ManualStimTriggerRequest(
        trigger=request.trigger - 1,
        triggerOn=request.trigger_on,
    )


def manual_stim_trigger_toggle_request_to_proto(
    request: ManualStimTriggerToggleRequest,
) -> allegoserver_pb2.ManualStimTriggerToggleRequest:
    """Convert ``ManualStimTriggerToggleRequest`` domain model → proto message."""
    # StimKeypressIndex is 1-indexed (1-8); proto expects 0-indexed (0-7)
    return allegoserver_pb2.ManualStimTriggerToggleRequest(
        trigger=request.trigger - 1,
    )


def build_stim_trigger_proto(
    trigger: StimKeypressIndex,
    on: bool,
) -> allegoserver_pb2.ManualStimTriggerRequest:
    """Build a ManualStimTriggerRequest proto from plain args."""
    # StimKeypressIndex is 1-indexed (1-8); proto expects 0-indexed (0-7)
    return allegoserver_pb2.ManualStimTriggerRequest(
        trigger=trigger - 1,
        triggerOn=on,
    )


def build_stim_trigger_toggle_proto(
    trigger: StimKeypressIndex,
) -> allegoserver_pb2.ManualStimTriggerToggleRequest:
    """Build a ManualStimTriggerToggleRequest proto from plain args."""
    # StimKeypressIndex is 1-indexed (1-8); proto expects 0-indexed (0-7)
    return allegoserver_pb2.ManualStimTriggerToggleRequest(
        trigger=trigger - 1,
    )
