export function createRuntimeTimelineState() {
  return {
    entries: [],
    artifacts: [],
    status: '',
    state: 'idle',
    lastEventId: 0,
    seenEventIds: {},
    heartbeatAt: null,
    elapsedMs: 0,
    providerSession: null,
    sessionId: '',
    startedAt: null,
    error: '',
  }
}

export function runtimeTimelineStatusLabel(timeline, isRunning) {
  if (isRunning) return timeline?.status || '运行时正在执行'
  if (timeline?.state === 'failed' || timeline?.error) return '运行时执行失败'
  if (timeline?.state === 'completed') return '运行时已完成'
  return timeline?.status || '运行时已结束'
}

function withEntry(state, entry) {
  return { ...state, entries: [...state.entries, entry] }
}

export function reduceRuntimeTimeline(state, event) {
  const current = state || createRuntimeTimelineState()
  if (!event || typeof event !== 'object') return current
  const eventId = Number(event.eventId ?? event.id ?? 0)
  if (eventId > 0 && current.seenEventIds[eventId]) return current

  const next = {
    ...current,
    lastEventId: eventId > 0 ? Math.max(current.lastEventId, eventId) : current.lastEventId,
    seenEventIds: eventId > 0
      ? { ...current.seenEventIds, [eventId]: true }
      : current.seenEventIds,
  }

  switch (event.t) {
    case 'session':
      return {
        ...next,
        sessionId: event.sessionId || next.sessionId,
        startedAt: next.startedAt || event.ts || new Date().toISOString(),
        state: 'running',
      }
    case 'status':
      return {
        ...withEntry(next, { type: 'status', content: String(event.v || ''), event }),
        status: String(event.v || next.status),
        startedAt: next.startedAt || event.ts || new Date().toISOString(),
        state: 'running',
      }
    case 'reasoning_summary':
      return event.v
        ? withEntry(next, { type: 'reasoning', content: String(event.v), event })
        : next
    case 'delta': {
      if (!event.v) return next
      const entries = [...next.entries]
      const last = entries.at(-1)
      if (last?.type === 'assistant') {
        entries[entries.length - 1] = { ...last, content: last.content + String(event.v), event }
      } else {
        entries.push({ type: 'assistant', content: String(event.v), event })
      }
      return { ...next, entries }
    }
    case 'tool_call':
      return withEntry(next, { type: 'tool_call', name: event.name, args: event.args, event })
    case 'tool_result':
      return withEntry(next, { type: 'tool_result', name: event.name, result: event.result, event })
    case 'artifact': {
      const artifact = event.artifact || {}
      const key = String(artifact.path || artifact.name || '')
      if (!key || next.artifacts.some(item => String(item.path || item.name || '') === key)) return next
      return {
        ...withEntry(next, { type: 'artifact', artifact, event }),
        artifacts: [...next.artifacts, artifact],
      }
    }
    case 'files': {
      const additions = (event.files || []).map(name => ({ name, path: name, sessionId: event.sessionId || '' }))
      const artifacts = [...next.artifacts]
      for (const artifact of additions) {
        const key = String(artifact.path || artifact.name || '')
        if (key && !artifacts.some(item => String(item.path || item.name || '') === key)) artifacts.push(artifact)
      }
      return { ...next, artifacts }
    }
    case 'warning':
    case 'warn':
      return withEntry(next, { type: 'warning', content: String(event.v || ''), event })
    case 'provider_session':
      return {
        ...next,
        providerSession: {
          provider: event.provider || '',
          id: event.providerSessionId || '',
          lastEventId: event.providerEventId || '',
        },
      }
    case 'heartbeat':
      return {
        ...next,
        heartbeatAt: event.ts || new Date().toISOString(),
        elapsedMs: Number(event.elapsedMs ?? next.elapsedMs ?? 0),
        state: event.state || next.state,
      }
    case 'error':
      return { ...withEntry(next, { type: 'error', content: String(event.v || ''), event }), error: String(event.v || ''), state: 'failed' }
    case 'done':
      return { ...next, state: event.state || 'completed' }
    default:
      return next
  }
}
