/**
 * SSE 事件调度器（B）— 把 MessageMapper 输出的 SSE event 映射到 AgentCallbacks 回调。
 *
 * process() 内部：for await msg → mapper.mapMessage(msg) → 对每个 event 调 dispatchSseEvent。
 * 这样复用 MessageMapper 的精细映射（agent_content/tool_raw_result/web_search），
 * 对外只暴露引擎无关的 AgentCallbacks。
 */

import type {
  AgentCallbacks,
  AgentContentEvent,
  AgentDoneEvent,
  AgentErrorEvent,
  AgentStartEvent,
  ApiRetryEvent,
  CancelledEvent,
  ErrorCategory,
  PlanReviewRequestEvent,
  QuestionRequestEvent,
  SessionInitEvent,
  TodoUpdateEvent,
  ToolSummaryEvent,
  WebSearchResultEvent,
} from '../../agent-types'
import type { SseEvent } from './message-mapper'

/** 把单个 SSE event 调度到对应的 AgentCallbacks 回调。 */
export async function dispatchSseEvent(event: SseEvent, callbacks: AgentCallbacks): Promise<void> {
  const e = event as Record<string, unknown>
  switch (event.type) {
    case 'text_delta':
      await callbacks.onTextDelta?.(e.text as string)
      break
    case 'thinking_start':
      await callbacks.onThinkingStart?.()
      break
    case 'thinking_delta':
      await callbacks.onThinkingDelta?.(e.text as string)
      break
    case 'tool_use_start':
      await callbacks.onToolUseStart?.(e.id as string, e.name as string)
      break
    case 'tool_use':
      await callbacks.onToolUse?.(e.id as string, e.name as string, e.input as Record<string, unknown>)
      break
    case 'tool_result':
      // mapper 的 tool_result（来自 tool_use_summary）name 可能为空串，透传（前端不用 name）
      await callbacks.onToolResult?.(e.tool_use_id as string, (e.name as string) ?? '', e.result as string, !!e.is_error)
      break
    case 'tool_raw_result':
      await callbacks.onToolRawResult?.(e.tool_use_id as string, e.tool_name as string, e.raw_content as Record<string, unknown>)
      break
    case 'tool_progress':
      await callbacks.onToolProgress?.(e.tool_use_id as string, e.tool_name as string, e.elapsed_time_seconds as number)
      break
    case 'agent_content':
      await callbacks.onAgentContent?.(e.parent_tool_use_id as string, mapAgentContent(event))
      break
    case 'question_request':
      await callbacks.onQuestionRequest?.({
        toolUseId: e.tool_use_id as string,
        input: e.input as QuestionRequestEvent['input'],
        questions: e.questions as unknown[],
      })
      break
    case 'plan_review_request':
      await callbacks.onPlanReviewRequest?.({
        toolUseId: e.tool_use_id as string,
        input: e.input as PlanReviewRequestEvent['input'],
        planContent: e.plan_content as string | undefined,
      })
      break
    case 'todo_update':
      await callbacks.onTodoUpdate?.({
        toolUseId: e.tool_use_id as string,
        input: e.input as TodoUpdateEvent['input'],
        todos: e.todos as unknown[],
      })
      break
    case 'session_init':
      await callbacks.onSessionInit?.({
        sessionId: e.session_id as string,
        model: e.model as string | undefined,
      })
      break
    case 'cancelled':
      await callbacks.onCancelled?.({
        reason: e.reason as CancelledEvent['reason'],
      })
      break
    case 'api_retry':
      await callbacks.onApiRetry?.({
        attempt: e.attempt as ApiRetryEvent['attempt'],
        maxRetries: e.max_retries as ApiRetryEvent['maxRetries'],
        retryDelayMs: e.retry_delay_ms as ApiRetryEvent['retryDelayMs'],
        errorStatus: e.error_status as ApiRetryEvent['errorStatus'],
        error: e.error as ApiRetryEvent['error'],
      })
      break
    case 'web_search_result':
      await callbacks.onWebSearchResult?.({
        toolUseId: e.tool_use_id as string,
        results: e.results as WebSearchResultEvent['results'],
      })
      break
    case 'tool_summary':
      await callbacks.onToolSummary?.({
        toolUseIds: e.tool_use_ids as ToolSummaryEvent['toolUseIds'],
        summary: e.summary as string,
      })
      break
    case 'agent_start':
      await callbacks.onAgentStart?.({
        parentToolUseId: e.parent_tool_use_id as string,
        description: e.description as AgentStartEvent['description'],
        prompt: e.prompt as AgentStartEvent['prompt'],
      })
      break
    case 'agent_done':
      await callbacks.onAgentDone?.({
        parentToolUseId: e.parent_tool_use_id as string,
        status: e.status as AgentDoneEvent['status'],
        inputTokens: e.input_tokens as AgentDoneEvent['inputTokens'],
        outputTokens: e.output_tokens as AgentDoneEvent['outputTokens'],
      })
      break
    case 'agent_error':
      await callbacks.onAgentError?.({
        parentToolUseId: e.parent_tool_use_id as string,
        error: e.error as string,
        category: e.category as AgentErrorEvent['category'],
      })
      break
    case 'error':
      await callbacks.onError?.(e.error as string, e.category as ErrorCategory | undefined)
      break
      // 'done' / 'attachment' 由消费方（route.ts）组装，不在 mapper 输出
  }
}

/** 把 mapper 的 agent_content SSE 扁平结构映射成 AgentContentEvent。 */
function mapAgentContent(event: SseEvent): AgentContentEvent {
  const e = event as Record<string, unknown>
  return {
    blockType: String(e.block_type ?? ''),
    text: e.text as string | undefined,
    id: e.id as string | undefined,
    name: e.name as string | undefined,
    input: e.input as Record<string, unknown> | undefined,
    toolUseId: e.tool_use_id as string | undefined,
    content: e.content,
    isError: e.is_error as boolean | undefined,
    elapsedSeconds: e.elapsed_time_seconds as number | undefined,
  }
}
