"""Unit tests for NaviWebSocketClient.send message framing.

``send`` accepts either a plain string (wrapped as a ``message``) or a dict
(sent as-is, with ``cwd`` defaulted) — the latter carries typed control
messages such as ``{"type": "compact"}``. These tests fake the socket so no
network is needed.
"""

from __future__ import annotations

import asyncio
import json

import pytest

from clients.terminal.ws_client import NaviWebSocketClient


class _FakeWs:
    def __init__(self) -> None:
        self.sent: list[str] = []

    async def send(self, raw: str) -> None:
        self.sent.append(raw)


def _client() -> NaviWebSocketClient:
    client = NaviWebSocketClient("sess")
    client._ws = _FakeWs()  # type: ignore[attr-defined]
    return client


def _sent_payloads(client: NaviWebSocketClient) -> list[dict]:
    return [json.loads(raw) for raw in client._ws.sent]  # type: ignore[attr-defined]


def test_send_string_wraps_as_message_with_cwd() -> None:
    client = _client()
    asyncio.run(client.send("hello"))
    [payload] = _sent_payloads(client)
    assert payload == {"type": "message", "content": "hello", "cwd": str(client._cwd)}


def test_send_dict_passes_through_with_default_cwd() -> None:
    client = _client()
    asyncio.run(client.send({"type": "compact"}))
    [payload] = _sent_payloads(client)
    assert payload["type"] == "compact"
    # cwd is defaulted in if absent.
    assert payload["cwd"] == str(client._cwd)


def test_send_dict_keeps_existing_cwd() -> None:
    client = _client()
    asyncio.run(client.send({"type": "compact", "cwd": "/custom"}))
    [payload] = _sent_payloads(client)
    assert payload == {"type": "compact", "cwd": "/custom"}


def test_send_raises_when_not_connected() -> None:
    client = NaviWebSocketClient("sess")  # no _ws set
    with pytest.raises(RuntimeError, match="not connected"):
        asyncio.run(client.send({"type": "compact"}))