"""Integration tests for audio streaming with real Icom radio.

Audio RX tests are safe (no transmission).
Audio TX tests are skipped by default (require antenna/dummy load).

Run with: pytest -m integration tests/integration/test_audio_integration.py

By default, RX tests require at least one audio packet to prove the stream works.
Override with ICOM_AUDIO_REQUIRE_PACKETS=0 if you only want start/stop smoke.
"""

from __future__ import annotations

import asyncio
import os
from typing import List

import pytest

from icom_lan import IcomRadio
from icom_lan.audio import AudioPacket


pytestmark = pytest.mark.integration


class TestAudioRx:
    """Audio receive tests (safe, no transmission)."""

    @staticmethod
    async def _run_rx_window(radio: IcomRadio, seconds: float = 2.0) -> list[AudioPacket]:
        packets: List[AudioPacket] = []

        def on_audio(pkt: AudioPacket) -> None:
            # Jitter buffer can emit None placeholders for gaps.
            if pkt is not None:
                packets.append(pkt)

        await radio.start_audio_rx(on_audio)
        await asyncio.sleep(seconds)
        await radio.stop_audio_rx()
        return packets

    @staticmethod
    def _require_packets() -> bool:
        return os.environ.get("ICOM_AUDIO_REQUIRE_PACKETS", "1") != "0"

    async def test_start_stop_audio_rx(self, radio: IcomRadio) -> None:
        """Start/stop RX and verify packet sanity."""
        packets = await self._run_rx_window(radio, seconds=2.0)

        print(f"Received {len(packets)} audio packets")

        if self._require_packets():
            assert packets, (
                "No audio packets received. "
                "Check radio audio settings/monitor and LAN audio availability. "
                "Set ICOM_AUDIO_REQUIRE_PACKETS=0 to run smoke-only."
            )

        # If packets exist, validate basic structure.
        if packets:
            first = packets[0]
            assert isinstance(first.ident, int)
            assert isinstance(first.send_seq, int)
            assert isinstance(first.data, bytes)
            assert len(first.data) > 0

    async def test_audio_rx_restart_cycle(self, radio: IcomRadio) -> None:
        """RX can be started/stopped repeatedly on one connection."""
        first = await self._run_rx_window(radio, seconds=1.5)
        second = await self._run_rx_window(radio, seconds=1.5)

        print(f"Cycle #1 packets: {len(first)}, cycle #2 packets: {len(second)}")

        if self._require_packets():
            assert first, "First RX cycle produced no audio packets"
            assert second, "Second RX cycle produced no audio packets"


class TestAudioTx:
    """Audio TX tests - SKIPPED by default (require antenna)."""

    @pytest.mark.skip(reason="Audio TX requires antenna - enable manually if needed")
    async def test_push_audio_tx(self, radio: IcomRadio) -> None:
        """Push audio data to TX (requires antenna!)."""
        await radio.start_audio_tx()

        # Push some silence (would need real Opus data in practice)
        # This is just a smoke test
        await asyncio.sleep(0.1)

        await radio.stop_audio_tx()
        print("Audio TX ✓")


class TestAudioSampleRate:
    """Sample rate configuration tests."""

    async def test_default_sample_rate(self, radio: IcomRadio) -> None:
        """Default sample rate should be 48000."""
        assert radio.audio_sample_rate == 48000
        print(f"Sample rate: {radio.audio_sample_rate} Hz ✓")

    async def test_custom_sample_rate(self, radio_config: dict) -> None:
        """Custom sample rate configuration."""
        radio = IcomRadio(**radio_config, audio_sample_rate=24000)
        await radio.connect()

        try:
            assert radio.audio_sample_rate == 24000
            print(f"Custom sample rate: {radio.audio_sample_rate} Hz ✓")
        finally:
            await radio.disconnect()
