from __future__ import annotations

import asyncio
import json
import unittest
from types import SimpleNamespace

from routes.tools import stream_tool_job
from tool_job_service import ToolJobService


class DummyRequest:
    async def is_disconnected(self) -> bool:
        return False


class ToolStreamRouteTests(unittest.IsolatedAsyncioTestCase):
    async def test_stream_tool_job_emits_current_and_terminal_updates(self) -> None:
        gate = asyncio.Event()

        async def send_request(method: str, params: dict[str, object]) -> dict[str, object]:
            gate.set()
            return {
                "tool_name": "demo.tool",
                "content": '{"ok": true}',
                "parsed": {"ok": True},
                "is_json": True,
            }

        service = ToolJobService(
            send_request=send_request,
            timeout_seconds=30.0,
            retention_seconds=60.0,
        )
        runtime = SimpleNamespace(tool_job_service=service)

        job = await service.start_job("demo.tool", {})
        await gate.wait()

        response = await stream_tool_job(job["job_id"], DummyRequest(), runtime=runtime)
        iterator = response.body_iterator

        first_chunk = await anext(iterator)
        self.assertEqual(first_chunk, ": stream-open\n\n")

        second_chunk = await anext(iterator)
        first_payload = json.loads(second_chunk.removeprefix("data: ").strip())
        self.assertEqual(first_payload["type"], "tool.job")
        self.assertEqual(first_payload["job"]["job_id"], job["job_id"])

        if first_payload["job"]["status"] == "completed":
            terminal_payload = first_payload
        else:
            third_chunk = await anext(iterator)
            terminal_payload = json.loads(third_chunk.removeprefix("data: ").strip())

        self.assertEqual(terminal_payload["job"]["status"], "completed")
        self.assertEqual(terminal_payload["job"]["result"]["tool_name"], "demo.tool")

        await iterator.aclose()
        await service.shutdown()
