import {
  buildStewardPlanMessageText,
  buildStewardPlanRequest,
  buildStewardSuggestedActions,
  isOffTopicStewardPlan,
  normalizeStewardPlan
} from './stewardPlanModel.js'
import { SESSION_TYPE_STEWARD } from './travelReimbursementConversationModel.js'
import { resolveStewardTypewriterNextIndex } from './stewardTypewriter.js'

const STEWARD_TYPEWRITER_INTERVAL_MS = 10
const STEWARD_THINKING_TYPEWRITER_INTERVAL_MS = 8
const STEWARD_TYPEWRITER_CHUNK_SIZE = 4
const STEWARD_THINKING_TYPEWRITER_CHUNK_SIZE = 5

export function useStewardPlanFlow({
  activeSessionType,
  attachedFiles,
  composerDraft,
  conversationId,
  currentUser,
  fileInputRef,
  messages,
  createMessage,
  fetchStewardPlan,
  fetchStewardPlanStream,
  nextTick,
  persistSessionState,
  replaceMessage,
  scrollToBottom,
  adjustComposerTextareaHeight,
  executeStewardSuggestedAction,
  submitting,
  reviewActionBusy,
  sessionSwitchBusy,
  stewardState,
  toast
}) {
  const stewardTypewriterTimers = new Map()
  let stewardTypewriterRunId = 0
  let stewardThinkingQueue = Promise.resolve()

  function isStewardSession() {
    return String(activeSessionType.value || '').trim() === SESSION_TYPE_STEWARD
  }

  function clearStewardThinkingTimers() {
    stewardTypewriterRunId += 1
    stewardThinkingQueue = Promise.resolve()
    for (const [timerId, resolve] of stewardTypewriterTimers.entries()) {
      globalThis.clearTimeout(timerId)
      resolve()
    }
    stewardTypewriterTimers.clear()
  }

  async function submitStewardPlan(options = {}) {
    if (!isStewardSession()) return false
    if (submitting.value || reviewActionBusy.value || sessionSwitchBusy.value) return true

    const rawText = String(options.rawText ?? composerDraft.value ?? '').trim()
    const files = Array.from(options.files ?? attachedFiles.value ?? [])
    if (!rawText && !files.length) return true

    const fileNames = files.map((file) => file.name).filter(Boolean)
    const userText = String(options.userText || rawText || `我上传了 ${fileNames.length} 份附件，请小财管家先归集任务。`).trim()
    if (isStewardConfirmationText(rawText) && !files.length) {
      const pendingContext = findPendingStewardAction()
      if (pendingContext) {
        if (!options.skipUserMessage) {
          messages.value.push(createMessage('user', userText))
        }
        pendingContext.action.confirmedByText = true
        composerDraft.value = ''
        persistSessionState()
        nextTick(() => {
          adjustComposerTextareaHeight()
          scrollToBottom()
        })
        await executeStewardSuggestedAction?.(pendingContext.message, pendingContext.action)
        return true
      }
    }

    submitting.value = true
    const streamRunId = beginStewardStreamRun()

    if (!options.skipUserMessage) {
      messages.value.push(createMessage('user', userText, fileNames))
    }
    const pendingPlan = normalizeStewardPlan({
      plan_status: 'streaming',
      summary: '',
      thinking_events: []
    })
    const pendingMessage = createMessage('assistant', '', [], {
      assistantName: '小财管家',
      meta: ['小财管家', '流式分析中'],
      stewardPlan: {
        ...pendingPlan,
        streamStatus: 'streaming'
      }
    })
    messages.value.push(pendingMessage)
    composerDraft.value = ''
    nextTick(() => {
      adjustComposerTextareaHeight()
      scrollToBottom()
    })

    try {
      const requestPayload = buildStewardPlanRequest({
        rawText,
        files,
        currentUser: currentUser.value || {},
        conversationId: conversationId?.value || '',
        stewardState: stewardState?.value || null
      })
      const plan = await fetchPlanWithStreaming(pendingMessage.id, requestPayload, streamRunId)
      const nextConversationId = String(plan?.conversation_id || plan?.conversationId || '').trim()
      if (nextConversationId && conversationId) {
        conversationId.value = nextConversationId
      }
      const nextStewardState = plan?.steward_state || plan?.stewardState || null
      if (nextStewardState && typeof nextStewardState === 'object' && stewardState) {
        stewardState.value = nextStewardState
      }
      await waitForStewardThinkingQueue(streamRunId)
      const typedThinkingEvents = resolveStewardThinkingEvents(pendingMessage.id)
      const normalizedPlan = normalizeStewardPlan(plan, {
        visibleThinkingEventCount: Number.MAX_SAFE_INTEGER,
        initialSummaryOnly: true
      })
      if (typedThinkingEvents.length) {
        normalizedPlan.thinkingEvents = typedThinkingEvents
        normalizedPlan.visibleThinkingEventCount = Number.MAX_SAFE_INTEGER
      }
      const finalText = buildStewardPlanMessageText(plan)
      const suggestedActions = buildStewardSuggestedActions(plan)
      replaceMessage(pendingMessage.id, createMessage('assistant', '', [], {
        id: pendingMessage.id,
        assistantName: '小财管家',
        meta: ['小财管家', '输出中'],
        stewardPlan: {
          ...normalizedPlan,
          streamStatus: 'typing'
        }
      }))
      await typeStewardPlanText(pendingMessage.id, finalText, normalizedPlan, suggestedActions, streamRunId)
      persistSessionState()
      nextTick(scrollToBottom)
    } catch (error) {
      replaceMessage(pendingMessage.id, createMessage('assistant', error?.message || '小财管家规划失败，请稍后重试。', [], {
        id: pendingMessage.id,
        assistantName: '小财管家',
        meta: ['小财管家', '规划失败']
      }))
      toast(error?.message || '小财管家规划失败，请稍后重试。')
      persistSessionState()
    } finally {
      submitting.value = false
      if (fileInputRef.value) {
        fileInputRef.value.value = ''
      }
      nextTick(() => {
        adjustComposerTextareaHeight()
        scrollToBottom()
      })
    }
    return true
  }

  function beginStewardStreamRun() {
    const runId = stewardTypewriterRunId + 1
    stewardTypewriterRunId = runId
    stewardThinkingQueue = Promise.resolve()
    return runId
  }

  async function typeStewardPlanText(messageId, finalText, normalizedPlan, suggestedActions = [], runId = stewardTypewriterRunId) {
    const chars = Array.from(String(finalText || ''))
    const total = chars.length
    let index = 0

    while (index < total) {
      if (runId !== stewardTypewriterRunId) {
        return
      }
      await waitStewardTypewriterTick(STEWARD_TYPEWRITER_INTERVAL_MS)
      if (runId !== stewardTypewriterRunId) {
        return
      }
      index = resolveStewardTypewriterNextIndex(chars, index, STEWARD_TYPEWRITER_CHUNK_SIZE)
      const message = messages.value.find((item) => item.id === messageId)
      if (!message) {
        return
      }
      message.text = chars.slice(0, index).join('')
      message.meta = ['小财管家', '输出中']
      message.stewardPlan = {
        ...(message.stewardPlan || normalizedPlan),
        ...normalizedPlan,
        streamStatus: 'typing'
      }
      if (index % 4 === 0 || index === total) {
        nextTick(scrollToBottom)
      }
    }

    const message = messages.value.find((item) => item.id === messageId)
    if (!message || runId !== stewardTypewriterRunId) {
      return
    }
    message.text = finalText
    message.meta = ['小财管家', '等待用户确认']
    message.stewardPlan = {
      ...(message.stewardPlan || normalizedPlan),
      ...normalizedPlan,
      streamStatus: 'completed'
    }
    message.suggestedActions = suggestedActions
    persistSessionState()
    nextTick(scrollToBottom)
  }

  function waitStewardTypewriterTick(intervalMs = STEWARD_TYPEWRITER_INTERVAL_MS) {
    return new Promise((resolve) => {
      const timerId = globalThis.setTimeout(() => {
        stewardTypewriterTimers.delete(timerId)
        resolve()
      }, intervalMs)
      stewardTypewriterTimers.set(timerId, resolve)
    })
  }

  function fetchPlanWithStreaming(messageId, requestPayload, runId) {
    if (typeof fetchStewardPlanStream === 'function') {
      return fetchStewardPlanStream(requestPayload, {
        onEvent: (event) => handleStreamEvent(messageId, event, runId)
      }, {
        timeoutMs: 12000,
        idleTimeoutMs: 120000,
        timeoutMessage: '小财管家任务规划超时，请稍后重试。'
      })
    }

    return fetchStewardPlan(requestPayload, {
      timeoutMs: 16000,
      timeoutMessage: '小财管家任务规划超时，请稍后重试。'
    })
  }

  function handleStreamEvent(messageId, event, runId = stewardTypewriterRunId) {
    if (event.event !== 'thinking') {
      return
    }
    stewardThinkingQueue = stewardThinkingQueue
      .then(() => typeStewardThinkingEvent(messageId, event.data, runId))
      .catch(() => {})
  }

  async function typeStewardThinkingEvent(messageId, eventData, runId) {
    if (runId !== stewardTypewriterRunId) {
      return
    }
    const eventId = String(eventData?.event_id || eventData?.eventId || `thinking-${Date.now()}`).trim()
    const title = String(eventData?.title || '').trim()
    const fullContent = String(eventData?.content || '').trim()
    appendStewardThinkingEvent(messageId, {
      ...eventData,
      event_id: eventId,
      eventId,
      title,
      content: '',
      status: 'running'
    }, runId)

    const chars = Array.from(fullContent)
    let index = 0
    while (index < chars.length) {
      if (runId !== stewardTypewriterRunId) {
        return
      }
      await waitStewardTypewriterTick(STEWARD_THINKING_TYPEWRITER_INTERVAL_MS)
      if (runId !== stewardTypewriterRunId) {
        return
      }
      index = resolveStewardTypewriterNextIndex(chars, index, STEWARD_THINKING_TYPEWRITER_CHUNK_SIZE)
      updateStewardThinkingEvent(messageId, eventId, chars.slice(0, index).join(''), 'running', runId)
    }

    updateStewardThinkingEvent(messageId, eventId, fullContent, 'completed', runId)
    persistSessionState()
  }

  function waitForStewardThinkingQueue(runId) {
    return stewardThinkingQueue.then(() => {
      if (runId !== stewardTypewriterRunId) {
        return
      }
    })
  }

  function resolveStewardThinkingEvents(messageId) {
    const message = messages.value.find((item) => item.id === messageId)
    return Array.isArray(message?.stewardPlan?.thinkingEvents)
      ? message.stewardPlan.thinkingEvents
      : []
  }

  function appendStewardThinkingEvent(messageId, eventData, runId) {
    if (runId !== stewardTypewriterRunId) {
      return
    }
    const message = messages.value.find((item) => item.id === messageId)
    if (!message?.stewardPlan) return
    const existingEvents = Array.isArray(message.stewardPlan.thinkingEvents)
      ? message.stewardPlan.thinkingEvents
      : []
    const normalizedPlan = normalizeStewardPlan({
      ...message.stewardPlan,
      thinking_events: [...existingEvents, eventData]
    }, {
      visibleThinkingEventCount: existingEvents.length + 1
    })
    message.stewardPlan = {
      ...message.stewardPlan,
      ...normalizedPlan,
      streamStatus: 'streaming'
    }
    persistSessionState()
    nextTick(scrollToBottom)
  }

  function updateStewardThinkingEvent(messageId, eventId, content, status, runId) {
    if (runId !== stewardTypewriterRunId) {
      return
    }
    const message = messages.value.find((item) => item.id === messageId)
    if (!message?.stewardPlan) return
    const existingEvents = Array.isArray(message.stewardPlan.thinkingEvents)
      ? message.stewardPlan.thinkingEvents
      : []
    const nextEvents = existingEvents.map((item) => (
      String(item.eventId || item.event_id || '').trim() === eventId
        ? {
            ...item,
            content,
            status
          }
        : item
    ))
    const normalizedPlan = normalizeStewardPlan({
      ...message.stewardPlan,
      thinking_events: nextEvents
    }, {
      visibleThinkingEventCount: nextEvents.length
    })
    message.stewardPlan = {
      ...message.stewardPlan,
      ...normalizedPlan,
      streamStatus: 'streaming'
    }
    if (content.length % 4 === 0 || status === 'completed') {
      nextTick(scrollToBottom)
    }
  }

  function findPendingStewardAction() {
    for (const message of [...messages.value].reverse()) {
      if (
        message?.role === 'assistant'
        && isPendingStewardActionMessage(message)
        && !message.suggestedActionsLocked
        && Array.isArray(message.suggestedActions)
        && message.suggestedActions.length
      ) {
        return {
          message,
          action: message.suggestedActions[0]
        }
      }
    }
    return null
  }

  function isPendingStewardActionMessage(message) {
    if (message?.stewardPlan) {
      if (message.stewardPlan.streamStatus === 'streaming') {
        return false
      }
      // off_topic 是引导用户重新编辑输入，不参与"确定/确认"快捷回复链路。
      if (isOffTopicStewardPlan(message.stewardPlan)) {
        return false
      }
      return true
    }
    return (
      String(message?.assistantName || '').trim() === '小财管家'
      && Array.isArray(message?.suggestedActions)
      && message.suggestedActions.some((action) =>
        String(action?.payload?.steward_plan_id || '').trim()
      )
    )
  }

  function isStewardConfirmationText(value) {
    const normalized = String(value || '').replace(/\s+/g, '')
    return /^(确定|确认|可以|好的|好|继续|继续执行|执行|开始执行|没问题|同意)$/.test(normalized)
  }

  return {
    isStewardSession,
    submitStewardPlan,
    clearStewardThinkingTimers
  }
}
