import { useAuthStore } from '@/stores/auth'

export type ChatStreamEventType =
  | 'message_meta'
  | 'text_delta'
  | 'thinking_delta'
  | 'usage'
  | 'done'
  | 'error'

export interface ChatStreamEvent {
  id: number
  event: ChatStreamEventType
  data: unknown
}

export interface ChatStreamHandlers {
  onEvent: (e: ChatStreamEvent) => void
  onClose?: () => void
  onError?: (err: Error) => void
}

export interface ChatStreamHandle {
  stop: () => void
}

/**
 * startChatStream 通过 fetch + ReadableStream 自实现 SSE 解析，
 * 以支持 Authorization Bearer 头（EventSource 不支持自定义 header）。
 * 同步返回 stop 句柄，读流在后台 fire-and-forget。
 *
 * 仅接受同源 streamUrl —— 防止上游配置错误把 Bearer token 发到外域。
 */
export function startChatStream(
  streamUrl: string,
  since: number,
  h: ChatStreamHandlers,
): ChatStreamHandle {
  const auth = useAuthStore()
  const url = new URL(streamUrl, window.location.origin)
  if (url.origin !== window.location.origin) {
    throw new Error('refusing cross-origin SSE')
  }
  url.searchParams.set('since', String(since))

  const ctrl = new AbortController()

  void (async () => {
    try {
      const headers: Record<string, string> = { Accept: 'text/event-stream' }
      if (auth.token) headers['Authorization'] = `Bearer ${auth.token}`
      const resp = await fetch(url.toString(), {
        headers,
        signal: ctrl.signal,
      })
      if (!resp.ok || !resp.body) {
        throw new Error(`SSE HTTP ${resp.status}`)
      }
      const reader = resp.body.getReader()
      const decoder = new TextDecoder()
      let buf = ''
      for (;;) {
        const { value, done } = await reader.read()
        if (done) break
        buf += decoder.decode(value, { stream: true })
        let idx = buf.indexOf('\n\n')
        while (idx >= 0) {
          const raw = buf.slice(0, idx)
          buf = buf.slice(idx + 2)
          const ev = parseSSE(raw)
          if (ev) h.onEvent(ev)
          idx = buf.indexOf('\n\n')
        }
      }
      h.onClose?.()
    } catch (err) {
      const e = err as { name?: string }
      if (e?.name === 'AbortError') return
      h.onError?.(err instanceof Error ? err : new Error(String(err)))
    }
  })()

  return { stop: () => ctrl.abort() }
}

function parseSSE(raw: string): ChatStreamEvent | null {
  let id = 0
  let event = ''
  const dataLines: string[] = []
  for (const line of raw.split('\n')) {
    if (line.startsWith('id:')) id = Number(line.slice(3).trim())
    else if (line.startsWith('event:')) event = line.slice(6).trim()
    else if (line.startsWith('data:')) dataLines.push(line.slice(5).trim())
  }
  if (!event) return null
  let data: unknown
  try {
    data = JSON.parse(dataLines.join('\n'))
  } catch {
    data = dataLines.join('\n')
  }
  return { id, event: event as ChatStreamEventType, data }
}
