"""Tests for the stream lifecycle state machine."""

from __future__ import annotations

import asyncio

import pytest

from device_agent.mqtt.stream_lifecycle import StreamLifecycle, StreamState


@pytest.mark.asyncio
async def test_initial_state():
    lc = StreamLifecycle()
    assert lc.state == StreamState.IDLE
    assert lc.viewer_count == 0


@pytest.mark.asyncio
async def test_viewer_connect_starts_streaming():
    started = []
    lc = StreamLifecycle(
        on_start_stream=lambda: _async_append(started, "start"),
    )
    await lc.viewer_connected()
    assert lc.state == StreamState.STREAMING
    assert lc.viewer_count == 1
    assert started == ["start"]


@pytest.mark.asyncio
async def test_viewer_disconnect_enters_cooldown():
    lc = StreamLifecycle(cooldown_seconds=0.1)
    await lc.viewer_connected()
    await lc.viewer_disconnected()
    assert lc.state == StreamState.COOLDOWN
    assert lc.viewer_count == 0


@pytest.mark.asyncio
async def test_cooldown_returns_to_idle():
    stopped = []
    lc = StreamLifecycle(
        cooldown_seconds=0.1,
        on_stop_stream=lambda: _async_append(stopped, "stop"),
    )
    await lc.viewer_connected()
    await lc.viewer_disconnected()
    await asyncio.sleep(0.2)
    assert lc.state == StreamState.IDLE
    assert stopped == ["stop"]


@pytest.mark.asyncio
async def test_new_viewer_cancels_cooldown():
    lc = StreamLifecycle(cooldown_seconds=10.0)
    await lc.viewer_connected()
    await lc.viewer_disconnected()
    assert lc.state == StreamState.COOLDOWN

    await lc.viewer_connected()
    assert lc.state == StreamState.STREAMING
    assert lc.viewer_count == 1


@pytest.mark.asyncio
async def test_multiple_viewers():
    lc = StreamLifecycle()
    await lc.viewer_connected()
    await lc.viewer_connected()
    assert lc.viewer_count == 2
    assert lc.state == StreamState.STREAMING

    await lc.viewer_disconnected()
    assert lc.viewer_count == 1
    assert lc.state == StreamState.STREAMING

    await lc.viewer_disconnected()
    assert lc.viewer_count == 0
    assert lc.state == StreamState.COOLDOWN


@pytest.mark.asyncio
async def test_force_stop():
    lc = StreamLifecycle()
    await lc.viewer_connected()
    await lc.force_stop()
    assert lc.state == StreamState.IDLE
    assert lc.viewer_count == 0


async def _async_append(lst: list, val: str) -> None:
    lst.append(val)
