# -*- coding: utf-8 -*-
"""
SSE 流式响应追踪辅助函数

提供一组轻量函数，在 SSE event_generator 内部调用，
追踪流式响应全过程（SSE_START → AI_CALL → SSE_EVENT → SSE_END / AI_ERROR）。

所有函数在无活跃 TraceContext 时静默跳过，不影响业务逻辑。
SSE_EVENT span 每 10 个 token 记录一次，避免 span 爆炸。
"""

from __future__ import annotations

from datetime import datetime

from app.trace.context import (
    SpanType,
    TraceSpan,
    TraceType,
    get_current_trace,
)


def record_sse_start(
    endpoint: str,
    user_id: int | None = None,
    chat_id: str = "",
) -> None:
    """记录 SSE_START span：流开始。

    同时将 trace_type 切换为 "sse"。
    """
    ctx = get_current_trace()
    if ctx is None:
        return

    # 切换 trace 类型为 SSE
    ctx.trace_type = TraceType.SSE

    ctx.add_span(TraceSpan(
        span_type=SpanType.SSE_START,
        module="trace.sse_wrapper",
        function="record_sse_start",
        description_zh=f"SSE 流开始: endpoint={endpoint}, chat_id={chat_id}",
        description_en=f"SSE stream started: endpoint={endpoint}, chat_id={chat_id}",
        params={"endpoint": endpoint, "user_id": user_id, "chat_id": chat_id},
        result_summary="",
        duration_ms=0.0,
        timestamp=datetime.now().isoformat(),
    ))


def record_ai_call(
    app_id: str,
    prompt_length: int,
    session_id: str = "",
) -> None:
    """记录 AI_CALL span：DashScope API 调用。"""
    ctx = get_current_trace()
    if ctx is None:
        return

    ctx.add_span(TraceSpan(
        span_type=SpanType.AI_CALL,
        module="trace.sse_wrapper",
        function="record_ai_call",
        description_zh=f"AI 调用: app_id={app_id}, prompt 长度={prompt_length}",
        description_en=f"AI call: app_id={app_id}, prompt_length={prompt_length}",
        params={
            "app_id": app_id,
            "prompt_length": prompt_length,
            "session_id": session_id,
        },
        result_summary="",
        duration_ms=0.0,
        timestamp=datetime.now().isoformat(),
    ))


def record_sse_token(token_count: int, total_tokens: int) -> None:
    """记录 SSE_EVENT span：每 10 个 token 记录一次，避免 span 爆炸。

    仅当 total_tokens 是 10 的倍数时才记录 span。
    """
    ctx = get_current_trace()
    if ctx is None:
        return

    # 每 10 个 token 记录一次
    if total_tokens % 10 != 0:
        return

    ctx.add_span(TraceSpan(
        span_type=SpanType.SSE_EVENT,
        module="trace.sse_wrapper",
        function="record_sse_token",
        description_zh=f"SSE token 流: 本批 {token_count} token, 累计 {total_tokens}",
        description_en=f"SSE token stream: batch {token_count}, cumulative {total_tokens}",
        params={"token_count": token_count, "total_tokens": total_tokens},
        result_summary=f"cumulative={total_tokens}",
        duration_ms=0.0,
        timestamp=datetime.now().isoformat(),
    ))


def record_sse_end(
    total_tokens: int,
    total_duration_ms: float,
    completed: bool = True,
) -> None:
    """记录 SSE_END span：流结束。"""
    ctx = get_current_trace()
    if ctx is None:
        return

    ctx.add_span(TraceSpan(
        span_type=SpanType.SSE_END,
        module="trace.sse_wrapper",
        function="record_sse_end",
        description_zh=f"SSE 流结束: 总 token={total_tokens}, 耗时={total_duration_ms:.0f}ms, 完成={completed}",
        description_en=f"SSE stream ended: total_tokens={total_tokens}, duration={total_duration_ms:.0f}ms, completed={completed}",
        params={
            "total_tokens": total_tokens,
            "total_duration_ms": total_duration_ms,
            "completed": completed,
        },
        result_summary=f"tokens={total_tokens}, completed={completed}",
        duration_ms=total_duration_ms,
        timestamp=datetime.now().isoformat(),
    ))


def record_ai_error(error_type: str, message: str) -> None:
    """记录 AI_ERROR span：AI 调用失败。"""
    ctx = get_current_trace()
    if ctx is None:
        return

    ctx.add_span(TraceSpan(
        span_type=SpanType.AI_ERROR,
        module="trace.sse_wrapper",
        function="record_ai_error",
        description_zh=f"AI 调用失败: {error_type} - {message}",
        description_en=f"AI call failed: {error_type} - {message}",
        params={"error_type": error_type, "message": message},
        result_summary=f"{error_type}: {message}",
        duration_ms=0.0,
        timestamp=datetime.now().isoformat(),
    ))
