"""Tests for the DecodedAudio immutable domain object."""

from __future__ import annotations

import dataclasses

import numpy as np

from decoder.decoded_audio import DecodedAudio


def _make_decoded_audio(
    samples: np.ndarray | None = None,
    sample_rate: int = 44100,
    channels: int = 1,
    duration: float = 1.0,
    bit_depth: int | None = 16,
) -> DecodedAudio:
    """Create a DecodedAudio with sensible defaults for testing.

    Args:
        samples: Optional NumPy array.  If ``None``, a small array
            of zeros is generated.
        sample_rate: Sample rate in Hz.
        channels: Number of channels.
        duration: Duration in seconds.
        bit_depth: Bit depth.

    Returns:
        A :class:`DecodedAudio` instance.
    """
    if samples is None:
        samples = np.zeros((int(sample_rate * duration), channels), dtype=np.float32)
    return DecodedAudio(
        samples=samples,
        sample_rate=sample_rate,
        channels=channels,
        duration=duration,
        bit_depth=bit_depth,
    )


def test_decoded_audio_is_frozen() -> None:
    """Verify that DecodedAudio is immutable."""
    audio = _make_decoded_audio()
    try:
        audio.sample_rate = 48000
        raise AssertionError("Should have raised FrozenInstanceError")
    except dataclasses.FrozenInstanceError:
        pass


def test_decoded_audio_fields() -> None:
    """Verify that DecodedAudio stores all fields correctly."""
    samples = np.ones((100, 2), dtype=np.float32)
    audio = DecodedAudio(
        samples=samples,
        sample_rate=22050,
        channels=2,
        duration=0.5,
        bit_depth=24,
    )
    assert audio.sample_rate == 22050
    assert audio.channels == 2
    assert audio.duration == 0.5
    assert audio.bit_depth == 24
    assert audio.samples.shape == (100, 2)


def test_decoded_audio_bit_depth_none() -> None:
    """Verify that bit_depth can be None."""
    audio = _make_decoded_audio(bit_depth=None)
    assert audio.bit_depth is None


def test_decoded_audio_samples_dtype() -> None:
    """Verify that samples are stored as provided."""
    samples = np.zeros((50, 1), dtype=np.float32)
    audio = _make_decoded_audio(samples=samples, channels=1)
    assert audio.samples.dtype == np.float32
