"""Integration tests for multi-session terminal WebSocket and REST API."""

import asyncio

import pytest
from fastapi.testclient import TestClient
from src.api.system.terminal import (
    MAX_TERMINAL_INPUT_BYTES,
    SessionRef,
    _queue_terminal_input,
    _write_loop,
)
from src.main import app


@pytest.fixture
def client():
    return TestClient(app)


class TestTerminalWebSocketMultiSession:
    """Tests for multi-session WebSocket routing."""

    def test_specific_session_websocket_route_exists(self, client):
        """The specific session WebSocket route should be registered."""
        # We can't easily test WebSocket without auth, but we can verify
        # the route exists by checking for a 403 (no auth cookie)
        response = client.get("/ws/tool-instances/test-instance/terminal/test-session")
        # WebSocket endpoint returns 403 when accessed via HTTP GET
        assert response.status_code == 403 or response.status_code == 404

    def test_default_session_alias_route_exists(self, client):
        """The default session alias route should still exist."""
        response = client.get("/ws/tool-instances/test-instance/terminal")
        assert response.status_code == 403 or response.status_code == 404


def test_terminal_input_queue_rejects_excess_input_without_blocking() -> None:
    """A stalled PTY writer cannot make the input queue grow without limit."""
    input_queue: asyncio.Queue[tuple[object, bytes]] = asyncio.Queue(maxsize=1)
    session = object()

    assert _queue_terminal_input(input_queue, session, b"first")
    assert not _queue_terminal_input(input_queue, session, b"second")
    assert not _queue_terminal_input(
        asyncio.Queue(), session, b"x" * (MAX_TERMINAL_INPUT_BYTES + 1)
    )


@pytest.mark.asyncio
async def test_ack_is_processed_while_a_pty_write_is_waiting() -> None:
    """A blocked paste writer must not block flow-control acknowledgements."""

    write_started = asyncio.Event()

    class Session:
        _closed = False

        def __init__(self) -> None:
            self.acks: list[int] = []
            self.write_finished = False

        def is_alive(self) -> bool:
            return True

        async def write_input(self, _data: bytes) -> None:
            write_started.set()
            try:
                await asyncio.Event().wait()
            finally:
                self.write_finished = True

        def acknowledge_data(self, char_count: int) -> None:
            self.acks.append(char_count)

    class WebSocket:
        def __init__(self) -> None:
            self.messages = iter(
                [
                    {"type": "websocket.receive", "bytes": b"large paste"},
                    {"type": "websocket.receive", "text": '{"type":"ack","chars":4096}'},
                    {"type": "websocket.disconnect"},
                ]
            )
            self.receive_count = 0

        async def receive(self):
            self.receive_count += 1
            if self.receive_count > 1:
                await write_started.wait()
            return next(self.messages)

    session = Session()
    websocket = WebSocket()
    task = asyncio.create_task(_write_loop(SessionRef(session), websocket, "instance"))

    await asyncio.wait_for(write_started.wait(), timeout=0.1)
    await asyncio.sleep(0)
    assert session.acks == [4096]

    await task
    assert session.write_finished


class TestTerminalRestApi:
    """Tests for REST API endpoints."""

    def test_list_sessions_requires_auth(self, client):
        """List sessions endpoint requires authentication."""
        response = client.get("/instances/test/terminal/sessions")
        assert response.status_code == 401

    def test_create_session_requires_auth(self, client):
        """Create session endpoint requires authentication."""
        response = client.post(
            "/instances/test/terminal/sessions",
            json={},
        )
        assert response.status_code == 401

    def test_close_session_requires_auth(self, client):
        """Close session endpoint requires authentication."""
        response = client.delete("/instances/test/terminal/sessions/test-session")
        assert response.status_code == 401

    def test_reset_session_requires_auth(self, client):
        """Reset session endpoint requires authentication."""
        response = client.post("/instances/test/terminal/sessions/test-session/reset")
        assert response.status_code == 401

    def test_rename_session_requires_auth(self, client):
        """Rename session endpoint requires authentication."""
        response = client.post(
            "/instances/test/terminal/sessions/test-session/rename",
            json={"name": "New Name"},
        )
        assert response.status_code == 401

    def test_legacy_reset_alias_requires_auth(self, client):
        """Legacy reset endpoint still requires auth."""
        response = client.post("/instances/test/terminal/reset")
        assert response.status_code == 401
