import asyncio
import json

import pytest

from gsearch_mcp_cli.core.cdp import CDPConnection, Tab


class FakeWebSocket:
    """Fake async WebSocket for testing."""
    def __init__(self, responses=None):
        self._responses = responses or []
        self._sent = []
        self._closed = False
        self._response_idx = 0

    async def send(self, data):
        self._sent.append(json.loads(data))

    async def recv(self):
        if self._response_idx < len(self._responses):
            resp = self._responses[self._response_idx]
            self._response_idx += 1
            return json.dumps(resp)
        await asyncio.sleep(10)

    async def close(self):
        self._closed = True

    def __aiter__(self):
        return self

    async def __anext__(self):
        try:
            return await self.recv()
        except (asyncio.CancelledError, IndexError):
            raise StopAsyncIteration


@pytest.mark.asyncio
async def test_cdp_connection_send_receives_response():
    ws = FakeWebSocket(responses=[{"id": 1, "result": {"value": 42}}])
    conn = CDPConnection()
    conn._ws = ws

    send_task = asyncio.create_task(conn.send("Test.method", {"key": "val"}))
    await asyncio.sleep(0.01)

    conn._reader_task = asyncio.create_task(conn._read_loop())

    result = await asyncio.wait_for(send_task, timeout=5)
    assert result["result"]["value"] == 42
    assert ws._sent[0]["method"] == "Test.method"

    conn._reader_task.cancel()
    try:
        await conn._reader_task
    except asyncio.CancelledError:
        pass


@pytest.mark.asyncio
async def test_cdp_connection_routes_by_id():
    ws = FakeWebSocket(responses=[
        {"id": 2, "result": {"second": True}},
        {"id": 1, "result": {"first": True}},
    ])
    conn = CDPConnection()
    conn._ws = ws

    result1_future = asyncio.create_task(conn.send("First", {}))
    await asyncio.sleep(0.01)
    result2_future = asyncio.create_task(conn.send("Second", {}))
    await asyncio.sleep(0.01)

    conn._reader_task = asyncio.create_task(conn._read_loop())

    result2 = await asyncio.wait_for(result2_future, timeout=2)
    result1 = await asyncio.wait_for(result1_future, timeout=2)

    assert result1["result"]["first"] is True
    assert result2["result"]["second"] is True

    conn._reader_task.cancel()
    try:
        await conn._reader_task
    except asyncio.CancelledError:
        pass


def test_tab_is_context_manager():
    """Tab should support async with syntax."""
    assert hasattr(Tab, '__aenter__')
    assert hasattr(Tab, '__aexit__')
