"""Tests for the Navi Code terminal client."""

from __future__ import annotations

import json
from pathlib import Path

import pytest
from click.testing import CliRunner

from clients.terminal.cli import main
from clients.terminal.config import Settings
from clients.terminal.render import Renderer
from clients.terminal.state import StateManager


class TestStateManager:
    def test_load_missing_returns_empty(self, tmp_path: Path) -> None:
        mgr = StateManager(tmp_path)
        assert mgr.load() == {}
        assert mgr.get_session_id() is None

    def test_roundtrip_session_id(self, tmp_path: Path) -> None:
        mgr = StateManager(tmp_path)
        mgr.set_session_id("sess-123")
        assert mgr.get_session_id() == "sess-123"
        assert (tmp_path / "state.json").exists()
        data = json.loads((tmp_path / "state.json").read_text())
        assert data == {"session_id": "sess-123"}

    def test_clear_session_id(self, tmp_path: Path) -> None:
        mgr = StateManager(tmp_path)
        mgr.set_session_id("sess-123")
        mgr.clear_session_id()
        assert mgr.get_session_id() is None


class TestRenderer:
    def test_stream_delta_prints_inline(self, capsys) -> None:
        renderer = Renderer()
        renderer.render({"type": "stream_delta", "delta": "hello"})
        captured = capsys.readouterr()
        assert "hello" in captured.out

    def test_error_prints_red(self, capsys) -> None:
        renderer = Renderer()
        renderer.render({"type": "error", "message": "boom"})
        captured = capsys.readouterr()
        assert "boom" in captured.out

    def test_tool_started_shown_when_events_enabled(self, capsys) -> None:
        renderer = Renderer(show_events=True)
        renderer.render({"type": "tool_started", "tool": "terminal", "args": {"cmd": "ls"}})
        captured = capsys.readouterr()
        assert "terminal" in captured.out

    def test_tool_started_hidden_when_events_disabled(self, capsys) -> None:
        renderer = Renderer(show_events=False)
        renderer.render({"type": "tool_started", "tool": "terminal", "args": {"cmd": "ls"}})
        captured = capsys.readouterr()
        assert captured.out == ""


class TestSettings:
    def test_websocket_url_converts_http_to_ws(self) -> None:
        s = Settings(base_url="http://localhost:8000")
        assert s.websocket_url("abc") == "ws://localhost:8000/ws/sessions/abc"

    def test_websocket_url_converts_https_to_wss(self) -> None:
        s = Settings(base_url="https://navi.example.com")
        assert s.websocket_url("abc") == "wss://navi.example.com/ws/sessions/abc"

    def test_websocket_url_uses_explicit_ws_url(self) -> None:
        s = Settings(ws_url="ws://custom:9000")
        assert s.websocket_url("abc") == "ws://custom:9000/ws/sessions/abc"


class TestCliRunner:
    def test_help_shows_usage(self) -> None:
        runner = CliRunner()
        result = runner.invoke(main, ["--help"])
        assert result.exit_code == 0
        assert "Navi Code" in result.output

    def test_version_shows_version(self) -> None:
        runner = CliRunner()
        result = runner.invoke(main, ["--version"])
        assert result.exit_code == 0
        assert "0.1.0" in result.output

    def test_raw_mode_uses_session_id_and_name_fields(
        self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
    ) -> None:
        """Raw CLI must read session_id/name/preview from the server API."""

        class FakeWsClient:
            def __init__(self, session_id: str, renderer=None, cwd=None) -> None:
                self.session_id = session_id
                self.cwd = cwd

            async def run_one_shot(self, prompt: str) -> None:
                pass

        monkeypatch.setattr("clients.terminal.cli.NaviWebSocketClient", FakeWsClient)

        from clients.terminal import config

        original_state_dir = config.settings.state_dir
        config.settings.state_dir = tmp_path

        def fake_create_session(profile_id: str | None = None) -> dict:
            return {
                "session_id": "sess-raw-1234",
                "profile_id": profile_id or "navi_code",
            }

        def fake_get_session(session_id: str) -> dict:
            return {
                "session_id": session_id,
                "profile_id": "navi_code",
                "name": "Raw session",
            }

        monkeypatch.setattr("clients.terminal.api.create_session", fake_create_session)
        monkeypatch.setattr("clients.terminal.api.get_session", fake_get_session)

        state = StateManager(tmp_path)
        state.set_session_id("sess-raw-1234")
        runner = CliRunner()
        try:
            result = runner.invoke(main, ["--raw", "--base-url", "http://localhost:8000", "hello"])
            assert result.exit_code == 0
            assert "Resumed session sess-raw" in result.output
        finally:
            config.settings.state_dir = original_state_dir
