"""Test websocket subscribe hydration only replays known active turns."""

from unittest.mock import MagicMock, patch

import pytest

from nanobot.channels.websocket.runtime import WebSocketChannel
from nanobot.webui.outbound_projection import WebUIOutboundProjector
from nanobot.webui.session_projection import WebUISessionProjection


@pytest.mark.asyncio
async def test_hydrate_after_subscribe_is_quiet_when_no_turn_active():
    """Subscribe hydration must not inject an idle event into normal message order."""
    channel = WebSocketChannel.__new__(WebSocketChannel)
    channel.gateway = MagicMock()
    channel.gateway.session_manager = MagicMock()
    channel.gateway.session_manager.read_session_metadata = MagicMock(return_value={})
    channel._session_projection = WebUISessionProjection(channel.gateway.session_manager)
    channel._outbound = WebUIOutboundProjector(channel, channel._session_projection)
    channel._turn_models = {}

    sent_events = []

    async def mock_send_goal_state(chat_id, blob):
        sent_events.append(("goal_state", chat_id, blob))

    async def mock_send_goal_status(chat_id, status, **kwargs):
        sent_events.append(("goal_status", chat_id, status, kwargs))

    channel.send_goal_state = mock_send_goal_state
    channel.send_goal_status = mock_send_goal_status

    with patch("nanobot.webui.session_projection.websocket_turn_wall_started_at", return_value=None):
        await channel._hydrate_after_subscribe("test-chat")

    assert sent_events == []


@pytest.mark.asyncio
async def test_hydrate_after_subscribe_pushes_running_when_turn_active():
    """Reconnecting client should receive running status when turn is active."""
    channel = WebSocketChannel.__new__(WebSocketChannel)
    channel.gateway = MagicMock()
    channel.gateway.session_manager = MagicMock()
    channel.gateway.session_manager.read_session_metadata = MagicMock(return_value={})
    channel._session_projection = WebUISessionProjection(channel.gateway.session_manager)
    channel._outbound = WebUIOutboundProjector(channel, channel._session_projection)
    channel._turn_models = {}

    sent_events = []

    async def mock_send_goal_state(chat_id, blob):
        sent_events.append(("goal_state", chat_id, blob))

    async def mock_send_goal_status(chat_id, status, **kwargs):
        sent_events.append(("goal_status", chat_id, status, kwargs))

    channel.send_goal_state = mock_send_goal_state
    channel.send_goal_status = mock_send_goal_status

    with (
        patch(
            "nanobot.webui.session_projection.websocket_turn_wall_started_at",
            return_value=1234567890.0,
        ),
        patch(
            "nanobot.webui.session_projection.websocket_turn_id",
            return_value="turn-active",
        ),
    ):
        await channel._hydrate_after_subscribe("test-chat")

    running_events = [e for e in sent_events if e[0] == "goal_status" and e[2] == "running"]
    assert len(running_events) == 1
    assert running_events[0][3]["started_at"] == 1234567890.0
    assert running_events[0][3]["turn_id"] == "turn-active"
