import { apiRequest, getRuntimeApiBaseUrl } from './api.js'
import {
  buildBearerHeaders,
  notifyAuthSessionExpired
} from '../utils/authSessionStorage.js'

export function fetchStewardPlan(payload, options = {}) {
  return apiRequest('/steward/plans', {
    method: 'POST',
    body: JSON.stringify(payload),
    ...options
  })
}

export function fetchStewardSlotDecision(payload, options = {}) {
  return apiRequest('/steward/slot-decisions', {
    method: 'POST',
    body: JSON.stringify(payload),
    ...options
  })
}

export function fetchStewardRuntimeDecision(payload, options = {}) {
  return apiRequest('/steward/runtime-decisions', {
    method: 'POST',
    body: JSON.stringify(payload),
    ...options
  })
}

export function executeStewardAction(payload, options = {}) {
  return apiRequest('/steward/actions/execute', {
    method: 'POST',
    body: JSON.stringify(payload),
    ...options
  })
}

export async function fetchStewardPlanStream(payload, handlers = {}, options = {}) {
  const {
    timeoutMs = 0,
    idleTimeoutMs = 90000,
    timeoutMessage = '小财管家任务规划超时，请稍后重试。'
  } = options
  const controller = typeof AbortController !== 'undefined' ? new AbortController() : null
  let timeoutId = 0
  const armAbortTimer = (delayMs) => {
    if (!controller) return
    if (timeoutId) {
      globalThis.clearTimeout(timeoutId)
      timeoutId = 0
    }
    if (Number(delayMs) > 0) {
      timeoutId = globalThis.setTimeout(() => controller.abort(), Number(delayMs))
    }
  }
  const clearAbortTimer = () => {
    if (timeoutId) {
      globalThis.clearTimeout(timeoutId)
      timeoutId = 0
    }
  }
  armAbortTimer(timeoutMs)

  let response
  try {
    response = await fetch(`${getRuntimeApiBaseUrl()}/steward/plans/stream`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...buildBearerHeaders()
      },
      body: JSON.stringify(payload),
      signal: controller?.signal
    })
  } catch (error) {
    clearAbortTimer()
    if (error?.name === 'AbortError') {
      throw new Error(timeoutMessage)
    }
    throw new Error('无法连接小财管家流式服务，请确认后端已启动。')
  }

  if (!response.ok) {
    clearAbortTimer()
    if (response.status === 401) {
      notifyAuthSessionExpired()
    }
    throw new Error(await resolveStreamError(response))
  }

  if (!response.body?.getReader) {
    const text = await response.text()
    clearAbortTimer()
    return consumeNdjsonText(text, handlers)
  }

  const decoder = new TextDecoder('utf-8')
  const reader = response.body.getReader()
  let buffer = ''
  let finalPlan = null

  try {
    armAbortTimer(idleTimeoutMs)
    while (true) {
      const { value, done } = await reader.read()
      if (done) {
        break
      }
      armAbortTimer(idleTimeoutMs)
      buffer += decoder.decode(value, { stream: true })
      const lines = buffer.split('\n')
      buffer = lines.pop() || ''
      for (const line of lines) {
        const event = parseStreamLine(line)
        if (!event) continue
        finalPlan = handleStreamEvent(event, handlers) || finalPlan
      }
    }

    buffer += decoder.decode()
    if (buffer.trim()) {
      const event = parseStreamLine(buffer)
      if (event) {
        finalPlan = handleStreamEvent(event, handlers) || finalPlan
      }
    }
  } catch (error) {
    if (error?.name === 'AbortError') {
      throw new Error(timeoutMessage)
    }
    throw error
  } finally {
    clearAbortTimer()
  }

  if (!finalPlan) {
    throw new Error('小财管家流式结果缺少最终任务计划。')
  }

  return finalPlan
}

async function resolveStreamError(response) {
  try {
    const payload = await response.json()
    return String(payload?.detail || payload?.message || '').trim() || '小财管家流式接口请求失败。'
  } catch {
    return '小财管家流式接口请求失败。'
  }
}

function consumeNdjsonText(text, handlers) {
  let finalPlan = null
  String(text || '').split('\n').forEach((line) => {
    const event = parseStreamLine(line)
    if (!event) return
    finalPlan = handleStreamEvent(event, handlers) || finalPlan
  })
  return finalPlan
}

function parseStreamLine(line) {
  const normalized = String(line || '').trim()
  if (!normalized) {
    return null
  }
  return JSON.parse(normalized)
}

function handleStreamEvent(event, handlers) {
  if (event.event === 'error') {
    throw new Error(String(event.data?.message || '').trim() || '小财管家规划失败，请稍后重试。')
  }
  handlers.onEvent?.(event)
  if (event.event === 'plan') {
    return event.data
  }
  return null
}
