"""Tests for FlexTimeRange and FlexSignalSpec coercion aliases."""

from __future__ import annotations

import pytest
from pydantic import BaseModel, ConfigDict, ValidationError

from radiens_core.models.dataset import FlexTimeRange, TimeRangeSpec, TrsMode
from radiens_core.models.signals import FlexSignalSpec, SignalSpec, SignalType

# ===================================================================
# Helper models that use the flex aliases
# ===================================================================


class _TimeRangeModel(BaseModel):
    model_config = ConfigDict(frozen=True)
    tr: FlexTimeRange


class _SignalSpecModel(BaseModel):
    model_config = ConfigDict(frozen=True)
    sig: FlexSignalSpec


# ===================================================================
# FlexTimeRange
# ===================================================================


class TestFlexTimeRange:
    def test_passthrough_spec(self) -> None:
        spec = TimeRangeSpec.subset(0, 10)
        m = _TimeRangeModel(tr=spec)
        assert m.tr is spec

    def test_list_subset(self) -> None:
        m = _TimeRangeModel(tr=[0, 10])
        assert isinstance(m.tr, TimeRangeSpec)
        assert m.tr.mode == TrsMode.SUBSET
        assert m.tr.start == 0
        assert m.tr.end == 10

    def test_tuple_subset(self) -> None:
        m = _TimeRangeModel(tr=(1.5, 3.5))
        assert isinstance(m.tr, TimeRangeSpec)
        assert m.tr.mode == TrsMode.SUBSET
        assert m.tr.start == 1.5
        assert m.tr.end == 3.5

    def test_list_lookback(self) -> None:

        m = _TimeRangeModel(tr=[5.0, float("nan")])
        assert isinstance(m.tr, TimeRangeSpec)
        assert m.tr.mode == TrsMode.FROM_HEAD
        assert m.tr.start == 5.0
        assert m.tr.end is None

    def test_invalid_type_raises(self) -> None:
        with pytest.raises(ValidationError):
            _TimeRangeModel(tr="invalid")  # type: ignore[arg-type]

    def test_invalid_type_string_raises(self) -> None:
        with pytest.raises(ValidationError):
            _TimeRangeModel(tr=42)  # type: ignore[arg-type]

    def test_wrong_length_list_raises(self) -> None:
        with pytest.raises(ValidationError):
            _TimeRangeModel(tr=[1, 2, 3])


# ===================================================================
# FlexSignalSpec
# ===================================================================


class TestFlexSignalSpec:
    def test_passthrough_spec(self) -> None:
        spec = SignalSpec.amp([0, 1, 2])
        m = _SignalSpecModel(sig=spec)
        assert m.sig is spec

    def test_list_of_ints_becomes_amp(self) -> None:
        m = _SignalSpecModel(sig=[0, 1, 2])
        assert isinstance(m.sig, SignalSpec)
        assert m.sig.sig_type == SignalType.AMP
        assert m.sig.channels == (0, 1, 2)

    def test_dict_becomes_multi(self) -> None:
        m = _SignalSpecModel(sig={"amp": [0, 1], "din": "all"})
        assert isinstance(m.sig, SignalSpec)
        assert m.sig.is_multi()
        assert m.sig.multi_select is not None
        assert SignalType.AMP in m.sig.multi_select
        assert SignalType.DIN in m.sig.multi_select

    def test_invalid_type_raises(self) -> None:
        with pytest.raises(ValidationError):
            _SignalSpecModel(sig="invalid")

    def test_invalid_type_int_raises(self) -> None:
        with pytest.raises(ValidationError):
            _SignalSpecModel(sig=42)  # type: ignore[arg-type]

    def test_empty_dict_raises(self) -> None:
        with pytest.raises(ValidationError):
            _SignalSpecModel(sig={})
