"""Synchronous streaming client for Kimi K2.5 via OpenRouter.

Runs entirely inside the agent's background thread (@work(thread=True)).
Uses httpx.Client (SYNC, not async) so the main Textual event loop is
never touched by network I/O.

Parses SSE (Server-Sent Events) line-by-line, yielding parsed JSON
chunks that the AgentBrain consumes for text streaming and tool-call
delta accumulation.
"""

from __future__ import annotations

import json
from typing import Generator

import httpx

from ..constants import AGENT_HTTP_TIMEOUT, OPENROUTER_BASE, OPENROUTER_MODEL


class OpenRouterClient:
    """Sync streaming HTTP client for OpenRouter's chat completions API."""

    def __init__(self, api_key: str, model: str = OPENROUTER_MODEL) -> None:
        self.api_key = api_key
        self.model = model
        self.client = httpx.Client(timeout=AGENT_HTTP_TIMEOUT)

    def stream_chat(
        self,
        messages: list[dict],
        tools: list[dict] | None = None,
    ) -> Generator[dict, None, None]:
        """Yield parsed SSE chunks from OpenRouter.

        Each yielded dict is the parsed JSON of one ``data:`` line
        from the SSE stream. The caller accumulates text content
        and tool_call deltas from these chunks.

        Raises httpx.HTTPStatusError on non-2xx responses.
        """
        payload: dict = {
            "model": self.model,
            "messages": messages,
            "stream": True,
        }
        if tools:
            payload["tools"] = tools
            payload["tool_choice"] = "auto"

        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
            "HTTP-Referer": "https://easyclaw.help",
            "X-Title": "EasyClaw Installer",
        }

        with self.client.stream(
            "POST", OPENROUTER_BASE, json=payload, headers=headers
        ) as response:
            response.raise_for_status()

            for line in response.iter_lines():
                if not line or line.startswith(":"):
                    continue  # skip empty lines and SSE comments

                if line.startswith("data: "):
                    data = line[6:]
                    if data.strip() == "[DONE]":
                        return
                    try:
                        yield json.loads(data)
                    except json.JSONDecodeError:
                        continue  # skip malformed chunks

    def close(self) -> None:
        """Close the underlying HTTP client."""
        self.client.close()
