"""Tests for DAC (Analog Output) functionality."""

from __future__ import annotations

from unittest.mock import patch

from radiens_core._generated import allegoserver_pb2
from radiens_core.allego_client import AllegoClient
from radiens_core.models.dac import AnalogOutRegister, DACHighPass


def test_dac_models() -> None:
    """Test DAC domain models initialization."""
    hp = DACHighPass(enable=True, cutoff_freq=1.0)
    assert hp.enable is True
    assert hp.cutoff_freq == 1.0

    from radiens_core.models.dac import AnalogOutChannel

    chan = AnalogOutChannel(pri_ntv_chan_idx=10, analog_out_ntv_chan_idx=0, stream=1, stream_offset_idx=0)
    assert chan.pri_ntv_chan_idx == 10
    assert chan.analog_out_ntv_chan_idx == 0

    reg = AnalogOutRegister(gain=1, highpass_reg=hp, channels=[chan])
    assert reg.gain == 1
    assert len(reg.channels) == 1
    assert reg.channels[0].pri_ntv_chan_idx == 10


def test_dac_converters() -> None:
    """Test DAC proto <-> domain converters."""
    from radiens_core._converters._dac import (
        analog_out_register_from_proto,
        dac_highpass_from_proto,
        dac_highpass_to_proto,
    )

    # Highpass
    proto_hp = allegoserver_pb2.DACHighPassRegister(enable=True, cutoffFreq=1.5)
    domain_hp = dac_highpass_from_proto(proto_hp)
    assert domain_hp.enable is True
    assert domain_hp.cutoff_freq == 1.5

    proto_hp_back = dac_highpass_to_proto(domain_hp)
    assert proto_hp_back.enable is True
    assert proto_hp_back.cutoffFreq == 1.5

    # Register
    proto_reg = allegoserver_pb2.AnalogOutRegister(gain=2)
    proto_reg.highpassReg.CopyFrom(proto_hp)
    proto_reg.analogOutChannels.add(PriNtvChanIdx=5, AnalogOutNtvChanIdx=1, Stream=1, StreamOffsetIdx=0)

    domain_reg = analog_out_register_from_proto(proto_reg)
    assert domain_reg.gain == 2
    assert domain_reg.highpass_reg.cutoff_freq == 1.5
    assert len(domain_reg.channels) == 1
    assert domain_reg.channels[0].pri_ntv_chan_idx == 5


def test_allego_client_dac_methods() -> None:
    """Test AllegoClient DAC methods call correct service functions."""
    with (
        patch("radiens_core._base_client.AuthInterceptor"),
        patch("radiens_core.allego_client.get_dac_reg_proto") as mock_get_reg,
        patch("radiens_core.allego_client.set_dac_gain_proto") as mock_set_gain,
        patch("radiens_core.allego_client.set_dac_stream_proto") as mock_set_stream,
        patch("radiens_core.allego_client.set_dac_off_proto") as mock_set_off,
        patch("radiens_core.allego_client.set_dac_highpass_proto") as mock_set_hp,
        patch("radiens_core.allego_client.validate_proto"),
    ):
        # Setup mock return for get_dac_reg
        proto_reg = allegoserver_pb2.AnalogOutRegister(gain=1)
        proto_reg.highpassReg.enable = False
        mock_get_reg.return_value = proto_reg

        client = AllegoClient()

        # get_dac_reg
        reg = client.get_dac_reg()
        assert reg.gain == 1
        mock_get_reg.assert_called_once()

        # set_dac_gain
        client.set_dac_gain(2)
        mock_set_gain.assert_called_once()
        args, _ = mock_set_gain.call_args
        assert args[2].gain == 2

        # set_dac_stream
        client.set_dac_stream(dac_idx=0, ntv_chan_idx=42)
        mock_set_stream.assert_called_once()
        args, _ = mock_set_stream.call_args
        assert args[2].DAC == 0
        assert args[2].NtvChanIdx == 42

        # set_dac_off
        client.set_dac_off()
        mock_set_off.assert_called_once()

        # set_dac_highpass
        client.set_dac_highpass(enable=True, cutoff_freq=150.0)
        mock_set_hp.assert_called_once()
        args, _ = mock_set_hp.call_args
        assert args[2].enable is True
        assert args[2].cutoffFreq == 150.0
