import { nextTick } from 'vue'
import {
  loadAiWorkbenchConversationHistory,
  saveAiWorkbenchConversation
} from '../../utils/aiWorkbenchConversationStore.js'

const INLINE_ANSWER_STREAM_CHUNK_SIZE = 6
const INLINE_ANSWER_STREAM_DELAY_MS = 24
const INLINE_AUTO_SCROLL_THRESHOLD = 96
const INLINE_LAYOUT_SETTLE_SCROLL_DELAY_MS = 260

export function useWorkbenchAiConversationRuntime(options) {
  const {
    activeConversationTitle,
    applicationSubmitConfirmContext,
    applicationSubmitConfirmOpen,
    assistantDraft,
    assistantInputRef,
    attachmentOcrExpandedMessageIds,
    clearAiModeFiles,
    clearWorkbenchDateSelection,
    conversationId,
    conversationMessages,
    conversationScrollRef,
    conversationStarted,
    currentUser,
    deleteDialogOpen,
    emit,
    inlineConversationAutoScrollPinned,
    searchConversationId,
    serializeRuntimeMessage,
    stewardState,
    thinkingCollapsedMessageIds,
    thinkingExpandedMessageIds
  } = options

  function focusAiModeInput() {
    nextTick(() => {
      assistantInputRef.value?.focus()
    })
  }

  function setAssistantInputRef(element) {
    assistantInputRef.value = element
  }

  function isInlineConversationNearBottom() {
    const el = conversationScrollRef.value
    if (!el) {
      return true
    }
    return el.scrollHeight - el.clientHeight - el.scrollTop <= INLINE_AUTO_SCROLL_THRESHOLD
  }

  function handleInlineConversationScroll() {
    inlineConversationAutoScrollPinned.value = isInlineConversationNearBottom()
  }

  function forceInlineConversationToBottom() {
    const el = conversationScrollRef.value
    if (el) {
      el.scrollTop = el.scrollHeight
      inlineConversationAutoScrollPinned.value = true
    }
  }

  function scrollInlineConversationToBottom(options = {}) {
    const shouldScroll = options.force !== false
    nextTick(() => {
      if (!shouldScroll) {
        return
      }
      forceInlineConversationToBottom()
      window.requestAnimationFrame(() => {
        forceInlineConversationToBottom()
      })
      window.setTimeout(() => {
        if (inlineConversationAutoScrollPinned.value) {
          forceInlineConversationToBottom()
        }
      }, INLINE_LAYOUT_SETTLE_SCROLL_DELAY_MS)
    })
  }

  function scrollInlineConversationToTop() {
    nextTick(() => {
      const el = conversationScrollRef.value
      if (el) {
        inlineConversationAutoScrollPinned.value = false
        el.scrollTo({ top: 0, behavior: 'smooth' })
      }
    })
  }

  function updateInlineMessageContent(message, content) {
    if (!message) {
      return
    }
    message.content = String(content || '')
    message.paragraphs = String(message.content || '')
      .split(/\n{2,}|\n/)
      .map((item) => item.trim())
      .filter(Boolean)
  }

  function appendInlineMessageContent(message, delta) {
    const nextDelta = String(delta || '')
    if (!nextDelta) {
      return
    }
    updateInlineMessageContent(message, `${message.content || ''}${nextDelta}`)
  }

  function waitInlineAnswerStreamFrame() {
    return new Promise((resolve) => {
      window.setTimeout(resolve, INLINE_ANSWER_STREAM_DELAY_MS)
    })
  }

  async function streamInlineAssistantContent(messageId, content) {
    const targetContent = String(content || '').trim()
    let streamedContent = ''

    for (let index = 0; index < targetContent.length; index += INLINE_ANSWER_STREAM_CHUNK_SIZE) {
      const message = conversationMessages.value.find((item) => item.id === messageId)
      if (!message || !message.pending) {
        return
      }
      const shouldAutoScroll = inlineConversationAutoScrollPinned.value
      streamedContent += targetContent.slice(index, index + INLINE_ANSWER_STREAM_CHUNK_SIZE)
      updateInlineMessageContent(message, streamedContent)
      scrollInlineConversationToBottom({ force: shouldAutoScroll })
      await waitInlineAnswerStreamFrame()
    }
  }

  async function streamOrSetInlineAssistantContent(messageId, content) {
    const targetContent = String(content || '').trim()
    if (/<!--\s*ai-trusted-html:start\s*-->/.test(targetContent)) {
      const message = conversationMessages.value.find((item) => item.id === messageId)
      if (message?.pending) {
        updateInlineMessageContent(message, targetContent)
        scrollInlineConversationToBottom({ force: inlineConversationAutoScrollPinned.value })
      }
      return
    }
    await streamInlineAssistantContent(messageId, targetContent)
  }

  function refreshConversationHistory() {
    const history = loadAiWorkbenchConversationHistory(currentUser.value || {})
    emit('conversation-history-change', history)
    return history
  }

  function isPersistableInlineConversation() {
    return Boolean(
      conversationId.value &&
        conversationId.value !== searchConversationId &&
        conversationMessages.value.length
    )
  }

  function persistCurrentConversation() {
    if (!isPersistableInlineConversation()) {
      refreshConversationHistory()
      return []
    }

    const history = saveAiWorkbenchConversation(currentUser.value || {}, {
      id: conversationId.value,
      conversationId: conversationId.value,
      title: activeConversationTitle.value,
      source: 'workbench',
      sessionType: 'steward',
      stewardState: stewardState.value,
      messages: conversationMessages.value.map((message) => serializeRuntimeMessage(message))
    })
    emit('conversation-history-change', history)
    return history
  }

  function resetInlineConversationState() {
    conversationStarted.value = false
    conversationMessages.value = []
    conversationId.value = ''
    stewardState.value = null
    activeConversationTitle.value = ''
    assistantDraft.value = ''
    thinkingExpandedMessageIds.value = new Set()
    thinkingCollapsedMessageIds.value = new Set()
    attachmentOcrExpandedMessageIds.value = new Set()
    deleteDialogOpen.value = false
    applicationSubmitConfirmOpen.value = false
    applicationSubmitConfirmContext.value = null
    clearWorkbenchDateSelection()
    clearAiModeFiles()
  }

  function replaceInlineMessage(id, nextMessage) {
    const index = conversationMessages.value.findIndex((item) => item.id === id)
    if (index === -1) {
      conversationMessages.value.push(nextMessage)
      return
    }
    conversationMessages.value.splice(index, 1, nextMessage)
  }

  function activateInlineConversation(options = {}) {
    conversationStarted.value = true
    if (!conversationId.value) {
      conversationId.value = options.id || `inline-${Date.now()}`
    }
    activeConversationTitle.value = options.title || activeConversationTitle.value || '新对话'
    emit('conversation-change', { id: conversationId.value, title: activeConversationTitle.value })
  }

  return {
    activateInlineConversation,
    appendInlineMessageContent,
    focusAiModeInput,
    handleInlineConversationScroll,
    persistCurrentConversation,
    refreshConversationHistory,
    replaceInlineMessage,
    resetInlineConversationState,
    scrollInlineConversationToBottom,
    scrollInlineConversationToTop,
    setAssistantInputRef,
    streamInlineAssistantContent,
    streamOrSetInlineAssistantContent,
    updateInlineMessageContent
  }
}
