from __future__ import annotations

import json
from collections.abc import Iterator
from typing import Any

from backend.llm import transport as llm_transport


class ReviewAssistantError(RuntimeError):
    pass


def stream_review_assistant(
    context: dict[str, Any],
    question: str,
    history: list[dict[str, str]],
    api_key: str,
    base_url: str,
    model: str,
    timeout: int = 120,
) -> Iterator[str]:
    if not api_key or not model:
        raise ReviewAssistantError("智能解读服务尚未配置。")
    messages = [{"role": "system", "content": _system_prompt(context)}]
    messages.extend(history[-12:])
    messages.append({"role": "user", "content": question})
    try:
        yield from llm_transport.stream_chat_completion(
            api_key=api_key,
            base_url=base_url,
            model=model,
            messages=messages,
            timeout=timeout,
            user_agent="XiaobaiReviewWeb/1.0",
        )
    except llm_transport.OpenAIEmptyResponseError as exc:
        raise ReviewAssistantError("智能解读未返回有效内容。") from exc
    except llm_transport.OpenAIHTTPError as exc:
        raise ReviewAssistantError(f"智能解读服务暂不可用（{exc.code}）。") from exc
    except llm_transport.OpenAITransportError as exc:
        raise ReviewAssistantError("智能解读连接中断，请稍后重试。") from exc


def _system_prompt(context: dict[str, Any]) -> str:
    context_json = json.dumps(context, ensure_ascii=False, separators=(",", ":"))
    return f"""
你是“小白复盘”的统一复盘助手。你负责把网页中已经存在的市场统计、策略跟踪、提醒、复盘笔记和手工交易日志连接起来，帮助用户复盘和形成下一步观察计划。

最高优先级规则：
1. 只能使用下方“网页复盘数据”，数据缺失就明确说明，不得补造行情、交易或胜率。
2. 不自动下单，不声称已执行任何操作，不修改策略、提醒、笔记或交易日志。
3. 不承诺收益，不给无条件买卖指令。建议必须写成条件、失效条件和风险边界。
4. 区分市场事实、用户记录和你的推断。引用数字时写明数据日期。
5. 优先结合用户自己的策略跟踪与交易日志寻找可验证的重复模式；样本不足时明确标注。
6. 使用中文，先直接回答，再给数据依据和下一步观察。避免空泛口号，不展示模型、接口或内部工程信息。
7. 控制在 800 个中文字符以内，除非用户明确要求展开。

网页复盘数据：
{context_json}
""".strip()
