import { ApiError } from './api'
import type { SSEEvent } from './types'

export function parseSSEBlock(block: string): SSEEvent | null {
  let eventName = ''
  const dataLines: string[] = []
  for (const line of block.split(/\r?\n/)) {
    if (!line || line.startsWith(':')) continue
    if (line.startsWith('event:')) eventName = line.slice(6).trim()
    if (line.startsWith('data:')) dataLines.push(line.slice(5).trimStart())
  }
  if (!eventName || dataLines.length === 0) return null
  return { event: eventName, data: JSON.parse(dataLines.join('\n')) } as SSEEvent
}

export async function streamSSE(
  path: string,
  body: unknown,
  onEvent: (event: SSEEvent) => void,
  signal: AbortSignal,
): Promise<void> {
  const response = await fetch(path, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
    signal,
  })
  if (!response.ok) {
    const payload = await response.json().catch(() => null)
    throw new ApiError(
      payload?.error?.message ?? `请求失败（${response.status}）`,
      payload?.error?.code ?? 'HTTP_ERROR',
      payload?.error?.request_id ?? response.headers.get('X-Request-ID') ?? '',
      payload?.error?.retryable ?? false,
      response.status,
    )
  }
  if (!response.body) throw new ApiError('浏览器未收到流式响应', 'EMPTY_STREAM', '', true)

  const reader = response.body.getReader()
  const decoder = new TextDecoder()
  let buffer = ''
  while (true) {
    const { value, done } = await reader.read()
    buffer += decoder.decode(value, { stream: !done }).replace(/\r\n/g, '\n')
    let boundary = buffer.indexOf('\n\n')
    while (boundary >= 0) {
      const block = buffer.slice(0, boundary)
      buffer = buffer.slice(boundary + 2)
      const event = parseSSEBlock(block)
      if (event) onEvent(event)
      boundary = buffer.indexOf('\n\n')
    }
    if (done) break
  }
  if (buffer.trim()) {
    const event = parseSSEBlock(buffer)
    if (event) onEvent(event)
  }
}
