import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useSystemState } from '../useSystemState.js'
import { useToast } from '../useToast.js'
import { useWorkbenchComposerDate } from '../useWorkbenchComposerDate.js'
import { fetchSettings } from '../../services/settings.js'
import { calculateTravelReimbursement, fetchExpenseClaimDetail } from '../../services/reimbursements.js'
import { useApplicationPreviewEditor } from '../../views/scripts/useApplicationPreviewEditor.js'
import {
  deleteAiWorkbenchConversation,
  markAiWorkbenchConversationDocumentDeleted
} from '../../utils/aiWorkbenchConversationStore.js'
import { renderAiConversationHtml } from '../../utils/aiConversationHtmlRenderer.js'
import {
  buildAiDocumentDetailRequest,
  parseAiApplicationDetailHref,
  parseAiDocumentDetailHref
} from '../../utils/aiDocumentDetailReference.js'
import {
  AI_MODE_ACTION_ITEMS,
  shouldRunAiAttachmentAutoAssociation
} from './workbenchAiComposerModel.js'
import {
  createWorkbenchAiMessageRuntime,
  formatMessageTime
} from './workbenchAiMessageModel.js'
import { useWorkbenchAiActionRouter } from './useWorkbenchAiActionRouter.js'
import { useWorkbenchAiAttachmentAssociationFlow } from './useWorkbenchAiAttachmentAssociationFlow.js'
import { useWorkbenchAiApplicationPreviewFlow } from './useWorkbenchAiApplicationPreviewFlow.js'
import { useWorkbenchAiComposerFiles } from './useWorkbenchAiComposerFiles.js'
import { useWorkbenchAiDocumentQueryFlow } from './useWorkbenchAiDocumentQueryFlow.js'
import { useWorkbenchAiExpenseFlow } from './useWorkbenchAiExpenseFlow.js'
import { useWorkbenchAiFilePreview } from './useWorkbenchAiFilePreview.js'
import { useWorkbenchAiMessageActions } from './useWorkbenchAiMessageActions.js'
import { useWorkbenchAiMessageExpansion } from './useWorkbenchAiMessageExpansion.js'
import { useWorkbenchAiSessionCommands } from './useWorkbenchAiSessionCommands.js'
import { useWorkbenchAiStewardFlow } from './useWorkbenchAiStewardFlow.js'
import {
  isReimbursementCreationIntent
} from './workbenchAiApplicationGateModel.js'
import { useWorkbenchAiCommandIntents } from './useWorkbenchAiCommandIntents.js'
import {
  shouldRequestWorkbenchAiIntentPlan
} from './workbenchAiIntentPlannerModel.js'
import { useWorkbenchAiConversationRuntime } from './useWorkbenchAiConversationRuntime.js'
import { useWorkbenchAiIntentExecution } from './useWorkbenchAiIntentExecution.js'

const AI_SEARCH_CONVERSATION_ID = 'ai-search'

export function usePersonalWorkbenchAiMode(props, emit) {
  const { currentUser } = useSystemState()
  const { toast } = useToast()
  const assistantDraft = ref('')
  const assistantInputRef = ref(null)
  const fileInputRef = ref(null)
  const conversationScrollRef = ref(null)
  const inlineConversationAutoScrollPinned = ref(true)
  const selectedFiles = ref([])
  const systemSettings = ref(null)
  const conversationStarted = ref(false)
  const conversationMessages = ref([])
  const conversationId = ref('')
  const activeConversationTitle = ref('')
  const sending = ref(false)
  const stewardState = ref(null)
  const aiExpenseDraft = ref(null)
  const thinkingExpandedMessageIds = ref(new Set())
  const thinkingCollapsedMessageIds = ref(new Set())
  const attachmentOcrExpandedMessageIds = ref(new Set())
  const deleteDialogOpen = ref(false)
  const applicationSubmitConfirmOpen = ref(false)
  const applicationSubmitConfirmContext = ref(null)
  const aiAttachmentAssociationRuntime = new Map()
  const messageRuntime = createWorkbenchAiMessageRuntime()
  const {
    createAiAttachmentAssociationId,
    createInlineMessage,
    normalizeRuntimeMessage,
    serializeRuntimeMessage
  } = messageRuntime
  const {
    applicationPreviewEditor,
    resolveApplicationPreviewEditorControl,
    resolveApplicationPreviewEditorDateMax,
    resolveApplicationPreviewEditorDateMin,
    resolveApplicationPreviewEditorOptions,
    refreshApplicationPreviewEstimate,
    isApplicationPreviewEditing,
    openApplicationPreviewEditor,
    commitApplicationPreviewEditor,
    cancelApplicationPreviewEditor,
    handleApplicationPreviewEditorKeydown
  } = useApplicationPreviewEditor({
    persistSessionState: () => persistCurrentConversation(),
    toast,
    calculateTravelReimbursement,
    currentUser
  })

  const {
    workbenchDatePickerOpen,
    workbenchDateMode,
    workbenchSingleDate,
    workbenchRangeStartDate,
    workbenchRangeEndDate,
    workbenchDateTagLabel,
    workbenchCanApplyDateSelection,
    clearWorkbenchDateSelection,
    toggleWorkbenchDatePicker,
    closeWorkbenchDatePicker,
    setWorkbenchDateMode,
    handleWorkbenchDatePickerOutside,
    applyWorkbenchDateSelection,
    handleWorkbenchDateInputChange,
    removeWorkbenchDateTag,
    buildWorkbenchPromptText
  } = useWorkbenchComposerDate({ draft: assistantDraft, focusInput: () => focusAiModeInput() })

  const conversationRuntime = useWorkbenchAiConversationRuntime({
    activeConversationTitle,
    applicationSubmitConfirmContext,
    applicationSubmitConfirmOpen,
    assistantDraft,
    assistantInputRef,
    attachmentOcrExpandedMessageIds,
    clearAiModeFiles: () => filesFlow.clearAiModeFiles(),
    clearWorkbenchDateSelection,
    conversationId,
    conversationMessages,
    conversationScrollRef,
    conversationStarted,
    currentUser,
    deleteDialogOpen,
    emit,
    inlineConversationAutoScrollPinned,
    searchConversationId: AI_SEARCH_CONVERSATION_ID,
    serializeRuntimeMessage,
    stewardState,
    thinkingCollapsedMessageIds,
    thinkingExpandedMessageIds
  })
  const {
    activateInlineConversation,
    appendInlineMessageContent,
    focusAiModeInput,
    handleInlineConversationScroll,
    persistCurrentConversation,
    refreshConversationHistory,
    replaceInlineMessage,
    resetInlineConversationState,
    scrollInlineConversationToBottom,
    scrollInlineConversationToTop,
    setAssistantInputRef,
    streamInlineAssistantContent,
    streamOrSetInlineAssistantContent,
    updateInlineMessageContent
  } = conversationRuntime

  const aiModeActionItems = AI_MODE_ACTION_ITEMS
  const displayUserName = computed(() => {
    const user = currentUser.value || {}
    return String(user.name || user.username || '同事').trim() || '同事'
  })
  const displayModelName = computed(() => {
    const llmForm = systemSettings.value?.llmForm
    if (!llmForm) return 'Axiom Ultra 3.1'
    const model = llmForm.mainModel || ''
    const provider = llmForm.mainProvider || ''
    if (!model) return 'Axiom Ultra 3.1'
    return provider ? `${provider} / ${model}` : model
  })
  const modelSelectorTitle = computed(() => {
    const llmForm = systemSettings.value?.llmForm
    if (!llmForm) return '当前模型：Axiom Ultra 3.1'
    const model = llmForm.mainModel || 'Axiom Ultra 3.1'
    const provider = llmForm.mainProvider || ''
    return provider ? `当前模型：${provider} / ${model}` : `当前模型：${model}`
  })

  const filesFlow = useWorkbenchAiComposerFiles({
    fileInputRef,
    focusAiModeInput,
    isInputLocked: () => isAiModeInputLocked.value,
    resolveInputLockedMessage: () => resolveAiModeInputLockMessage(),
    selectedFiles,
    toast
  })

  const documentQueryFlow = useWorkbenchAiDocumentQueryFlow({
    conversationMessages,
    createInlineMessage,
    inlineConversationAutoScrollPinned,
    persistCurrentConversation,
    replaceInlineMessage,
    scrollInlineConversationToBottom
  })

  const commandIntents = useWorkbenchAiCommandIntents({
    activateInlineConversation,
    activeConversationTitle,
    assistantDraft,
    clearAiModeFiles: filesFlow.clearAiModeFiles,
    closeWorkbenchDatePicker,
    conversationId,
    conversationMessages,
    createInlineMessage,
    documentQueryFlow,
    inlineConversationAutoScrollPinned,
    persistCurrentConversation,
    removeWorkbenchDateTag,
    scrollInlineConversationToBottom,
    searchConversationId: AI_SEARCH_CONVERSATION_ID,
    sending
  })

  const attachmentFlow = useWorkbenchAiAttachmentAssociationFlow({
    aiAttachmentAssociationRuntime,
    conversationId,
    conversationMessages,
    createAiAttachmentAssociationId,
    createInlineMessage,
    inlineConversationAutoScrollPinned,
    persistCurrentConversation,
    replaceInlineMessage,
    scrollInlineConversationToBottom,
    sending,
    streamOrSetInlineAssistantContent,
    notifyRequestUpdated: (payload) => emit('request-updated', payload),
    toast
  })

  const filePreview = useWorkbenchAiFilePreview({
    attachmentFlow,
    conversationStarted,
    scrollInlineConversationToBottom,
    selectedFiles
  })
  const {
    hasInlineAttachmentOcrDetails,
    hasInlineThinking,
    isInlineAttachmentOcrExpanded,
    isInlineThinkingExpanded,
    resolveInlineAttachmentOcrDocuments,
    resolveInlineAttachmentOcrFileCount,
    resolveInlineThinkingEvents,
    toggleInlineAttachmentOcrDetails,
    toggleInlineThinking
  } = useWorkbenchAiMessageExpansion({
    attachmentOcrExpandedMessageIds,
    inlineConversationAutoScrollPinned,
    scrollInlineConversationToBottom,
    thinkingCollapsedMessageIds,
    thinkingExpandedMessageIds
  })

  let intentExecution = null

  const applicationFlow = useWorkbenchAiApplicationPreviewFlow({
    activateInlineConversation,
    applicationPreviewEditor,
    applicationSubmitConfirmContext,
    applicationSubmitConfirmOpen,
    assistantDraft,
    cancelApplicationPreviewEditor,
    clearAiModeFiles: filesFlow.clearAiModeFiles,
    closeWorkbenchDatePicker,
    commitApplicationPreviewEditor,
    conversationId,
    conversationMessages,
    conversationStarted,
    createInlineMessage,
    currentUser,
    handleApplicationPreviewEditorKeydown,
    inlineConversationAutoScrollPinned,
    isApplicationPreviewEditing,
    openApplicationPreviewEditor,
    persistCurrentConversation,
    pushInlineApplicationActionUserMessage,
    pushInlineUserMessage,
    refreshApplicationPreviewEstimate,
    removeWorkbenchDateTag,
    replaceInlineMessage,
    resolveApplicationPreviewEditorDateMax,
    resolveApplicationPreviewEditorDateMin,
    resolveApplicationPreviewEditorControl,
    resolveApplicationPreviewEditorOptions,
    resolveInlineThinkingEvents,
    resolveLatestInlineUserPrompt,
    scrollInlineConversationToBottom,
    sending,
    toast,
    onApplicationActionCompleted: (remainingTasks) => intentExecution?.startModelPlannedNextTask(remainingTasks)
  })

  const expenseFlow = useWorkbenchAiExpenseFlow({
    activateInlineConversation,
    aiExpenseDraft,
    assistantDraft,
    clearAiModeFiles: filesFlow.clearAiModeFiles,
    closeWorkbenchDatePicker,
    conversationMessages,
    conversationStarted,
    createInlineMessage,
    currentUser,
    persistCurrentConversation,
    pushInlineUserMessage,
    replaceInlineMessage,
    removeWorkbenchDateTag,
    resolveLatestInlineUserPrompt,
    scrollInlineConversationToBottom,
    startAiApplicationPreview: applicationFlow.startAiApplicationPreview
  })

  const actionRouter = useWorkbenchAiActionRouter({
    aiExpenseDraft,
    applicationFlow,
    assistantDraft,
    attachmentFlow,
    conversationMessages,
    createInlineMessage,
    emit,
    expenseFlow,
    focusAiModeInput,
    hasInlineAttachmentOcrDetails,
    persistCurrentConversation,
    replaceInlineMessage,
    resolveLatestInlineUserPrompt,
    scrollInlineConversationToBottom,
    selectedFiles,
    startInlineConversation,
    toast,
    toggleInlineAttachmentOcrDetails
  })

  const sessionCommands = useWorkbenchAiSessionCommands({
    activeConversationTitle,
    attachmentOcrExpandedMessageIds,
    conversationId,
    conversationMessages,
    conversationStarted,
    createInlineMessage,
    currentUser,
    deleteAiWorkbenchConversation,
    emit,
    focusAiModeInput,
    inlineConversationAutoScrollPinned,
    normalizeRuntimeMessage,
    refreshConversationHistory,
    resetInlineConversationState,
    scrollInlineConversationToBottom,
    stewardState,
    thinkingCollapsedMessageIds,
    thinkingExpandedMessageIds,
    toast
  })

  const messageActions = useWorkbenchAiMessageActions({
    assistantDraft,
    focusAiModeInput,
    persistCurrentConversation,
    toast
  })

  const stewardFlow = useWorkbenchAiStewardFlow({
    activeConversationTitle,
    collectAiModeReceiptContext: attachmentFlow.collectAiModeReceiptContext,
    conversationId,
    conversationMessages,
    createInlineMessage,
    currentUser,
    deleteAiWorkbenchConversation,
    emit,
    handleAiDocumentQueryIntent: documentQueryFlow.handleAiDocumentQueryIntent,
    inlineConversationAutoScrollPinned,
    persistCurrentConversation,
    replaceInlineMessage,
    resolveInlineThinkingEvents,
    scrollInlineConversationToBottom,
    sending,
    stewardState,
    streamInlineAssistantContent,
    updateInlineMessageContent,
    appendInlineMessageContent,
    toast
  })

  intentExecution = useWorkbenchAiIntentExecution({
    actionRouter,
    activeConversationTitle,
    activateInlineConversation,
    applicationFlow,
    assistantDraft,
    clearAiModeFiles: filesFlow.clearAiModeFiles,
    closeWorkbenchDatePicker,
    conversationId,
    conversationMessages,
    createInlineMessage,
    expenseFlow,
    inlineConversationAutoScrollPinned,
    persistCurrentConversation,
    removeWorkbenchDateTag,
    replaceInlineMessage,
    resolveInlineThinkingEvents,
    scrollInlineConversationToBottom,
    searchConversationId: AI_SEARCH_CONVERSATION_ID,
    sending,
    stewardFlow
  })

  const applicationPreviewEstimatePending = computed(() => (
    conversationMessages.value.some((message) => applicationFlow.isApplicationPreviewEstimatePending(message))
  ))
  const isAiModeReceiptRecognitionPending = computed(() => attachmentFlow.hasPendingAiModeReceiptRecognition(selectedFiles.value))
  const hasAiModeReceiptRecognitionFailure = computed(() => attachmentFlow.hasFailedAiModeReceiptRecognition(selectedFiles.value))
  const isAiModeInputLocked = computed(() => applicationPreviewEstimatePending.value || isAiModeReceiptRecognitionPending.value)
  const aiModeInputLockMessage = computed(() => resolveAiModeInputLockMessage())
  const canSubmitAiModePrompt = computed(() => (
    !isAiModeInputLocked.value &&
    !hasAiModeReceiptRecognitionFailure.value && (
      Boolean(assistantDraft.value.trim()) ||
      selectedFiles.value.length > 0 ||
      Boolean(workbenchDateTagLabel.value)
    )
  ))

  async function loadSystemSettings() {
    try {
      systemSettings.value = await fetchSettings()
    } catch {
      systemSettings.value = { llmForm: {} }
    }
  }

  function renderInlineConversationHtml(content) { return renderAiConversationHtml(content) }

  function isUnavailableDocumentDetailError(error) {
    const message = String(error?.message || '').trim()
    return /not\s*found|不存在|已删除|不可访问|无权|forbidden|404/i.test(message)
  }

  function resolveDocumentDetailLookupClaimId(detailRequest = {}) {
    return String(detailRequest.claimId || detailRequest.claim_id || '').trim()
  }

  function markActiveAiDocumentDetailLinkDeleted(detailRequest = {}) {
    const nextHistory = markAiWorkbenchConversationDocumentDeleted(currentUser.value || {}, {
      claimId: detailRequest.claimId,
      claim_id: detailRequest.claimId,
      claimNo: detailRequest.claimNo,
      claim_no: detailRequest.claimNo,
      documentNo: detailRequest.documentNo,
      document_no: detailRequest.documentNo,
      id: detailRequest.id
    })
    emit('conversation-history-change', nextHistory)
    const activeConversation = nextHistory.find((item) => (
      String(item.id || item.conversationId || '').trim() === String(conversationId.value || '').trim()
    ))
    if (activeConversation?.messages?.length) {
      conversationMessages.value = activeConversation.messages.map((message) => normalizeRuntimeMessage(message))
      scrollInlineConversationToBottom({ force: inlineConversationAutoScrollPinned.value })
    }
  }

  async function ensureAiDocumentDetailStillAvailable(detailRequest = {}) {
    const claimId = resolveDocumentDetailLookupClaimId(detailRequest)
    if (!claimId) {
      return true
    }
    try {
      await fetchExpenseClaimDetail(claimId)
      return true
    } catch (error) {
      if (!isUnavailableDocumentDetailError(error)) {
        console.warn('AI document detail availability check failed, continuing navigation:', error)
        return true
      }
      markActiveAiDocumentDetailLinkDeleted(detailRequest)
      toast('该单据已经删除或不可访问，已将这条历史入口标记为不可查看。')
      return false
    }
  }

  function buildInlinePromptText(rawPrompt, files = []) {
    const prompt = buildWorkbenchPromptText(rawPrompt)
    if (prompt) return prompt
    return files.length ? '请帮我处理已上传的附件。' : ''
  }

  function resolveAiModeInputLockMessage() {
    if (isAiModeReceiptRecognitionPending.value) {
      return '附件识别中，请稍等...'
    }
    if (applicationPreviewEstimatePending.value) {
      return '费用测算中，请稍等...'
    }
    return ''
  }

  function resolveAiModeSubmitBlockedMessage() {
    if (applicationPreviewEstimatePending.value) {
      return '请等待费用测算完成后再继续操作。'
    }
    if (isAiModeReceiptRecognitionPending.value) {
      return '附件 OCR 识别中，请稍等，识别完成后再继续对话。'
    }
    if (hasAiModeReceiptRecognitionFailure.value) {
      return '请先移除识别失败的附件或重新上传。'
    }
    return ''
  }

  function ensureAiModeCanStartConversation() {
    const blockedMessage = resolveAiModeSubmitBlockedMessage()
    if (!blockedMessage) {
      return true
    }
    toast(blockedMessage)
    focusAiModeInput()
    return false
  }

  async function handleAiAnswerMarkdownClick(event) {
    const target = event?.target
    const link = target?.closest?.('a[href^="#ai-open-document-detail:"], a[href^="#ai-open-application-detail:"]')
    if (!link) {
      return
    }
    const href = link.getAttribute('href')
    const detailReference = parseAiDocumentDetailHref(href) || parseAiApplicationDetailHref(href)
    if (!detailReference) {
      return
    }
    event.preventDefault()
    event.stopPropagation()
    const detailRequest = buildAiDocumentDetailRequest(detailReference)
    if (!(await ensureAiDocumentDetailStillAvailable(detailRequest))) {
      return
    }
    emit('open-document', detailRequest)
  }

  function startInlineConversation(prompt, entry = {}, files = []) {
    if (!ensureAiModeCanStartConversation()) {
      return
    }
    const cleanPrompt = buildInlinePromptText(prompt, files)
    if (!cleanPrompt || sending.value) {
      return
    }

    if (commandIntents.handleInlineDraftDeletionIntent(cleanPrompt, entry)) {
      return
    }

    if (applicationFlow.handleInlineApplicationPreviewTextAction(cleanPrompt, applicationPreviewEstimatePending)) {
      return
    }

    if (aiExpenseDraft.value && !isAiExpenseDraftComplete(aiExpenseDraft.value)) {
      expenseFlow.advanceAiExpenseDraft(cleanPrompt, files)
      return
    }

    if (shouldRequestWorkbenchAiIntentPlan(cleanPrompt)) {
      void intentExecution.executeModelPlannedWorkbenchIntent(cleanPrompt, entry, files)
      return
    }

    if (isReimbursementCreationIntent(cleanPrompt)) {
      void expenseFlow.startAiReimbursementAssociationGate(cleanPrompt, entry.label || '我要报销')
      return
    }

    if (conversationId.value === AI_SEARCH_CONVERSATION_ID) {
      conversationId.value = ''
      conversationMessages.value = []
      activeConversationTitle.value = ''
    }

    sending.value = true
    activateInlineConversation({
      title: entry.label || cleanPrompt.slice(0, 18) || '新对话'
    })
    inlineConversationAutoScrollPinned.value = true
    conversationMessages.value.push(createInlineMessage('user', cleanPrompt))
    assistantDraft.value = ''
    removeWorkbenchDateTag()
    closeWorkbenchDatePicker()
    filesFlow.clearAiModeFiles()
    scrollInlineConversationToBottom()
    persistCurrentConversation()
    if (shouldRunAiAttachmentAutoAssociation(entry, files, cleanPrompt)) {
      void attachmentFlow.requestAiAttachmentAssociationReply(cleanPrompt, entry, files)
      return
    }
    void stewardFlow.requestInlineAssistantReply(cleanPrompt, entry, files)
  }

  function submitAiModePrompt() {
    if (!ensureAiModeCanStartConversation()) {
      return
    }
    if (!canSubmitAiModePrompt.value) {
      toast('请输入需求后再发送。')
      focusAiModeInput()
      return
    }
    startInlineConversation(assistantDraft.value, { source: 'workbench', sessionType: 'steward' }, Array.from(selectedFiles.value))
  }

  function runAiModeAction(item) {
    if (!ensureAiModeCanStartConversation()) {
      return
    }
    if (String(item?.label || '').trim() === '发起报销') {
      void expenseFlow.startAiReimbursementAssociationGate(item.prompt, item.label)
      return
    }
    startInlineConversation(item.prompt, item, Array.from(selectedFiles.value))
  }

  function regenerateLastReply() {
    const lastUserMessage = [...conversationMessages.value].reverse().find((message) => message.role === 'user')
    if (!lastUserMessage || sending.value) {
      return
    }
    const lastAssistantIndex = conversationMessages.value.map((message) => message.role).lastIndexOf('assistant')
    if (lastAssistantIndex >= 0) {
      conversationMessages.value.splice(lastAssistantIndex, 1)
    }
    sending.value = true
    void stewardFlow.requestInlineAssistantReply(lastUserMessage.content, { source: 'workbench', sessionType: 'steward' }, [])
  }

  function pushInlineUserMessage(text) { conversationMessages.value.push(createInlineMessage('user', String(text || '').trim())) }

  function pushInlineApplicationActionUserMessage(text) {
    pushInlineUserMessage(text)
    assistantDraft.value = ''
    removeWorkbenchDateTag()
    closeWorkbenchDatePicker()
    filesFlow.clearAiModeFiles()
  }

  function resolveLatestInlineUserPrompt() {
    return String([...conversationMessages.value].reverse().find((message) => message.role === 'user')?.content || '').trim()
  }

  function handleVoiceInput() {
    if (!ensureAiModeCanStartConversation()) {
      return
    }
    toast('语音输入正在准备中，您可以先输入文字需求。')
    focusAiModeInput()
  }

  watch(
    () => props.sidebarCommand?.seq,
    () => {
      const command = props.sidebarCommand || {}
      if (command.type === 'new-chat') {
        sessionCommands.startNewInlineConversation()
        return
      }
      if (command.type === 'search-chat') {
        sessionCommands.openInlineSearchConversation(activateInlineConversation)
        return
      }
      if (command.type === 'open-recent') {
        sessionCommands.openInlineRecentConversation(command.payload || {})
        attachmentFlow.resumePendingAiAttachmentAssociationJobs()
        expenseFlow.resumePendingLinkedReimbursementDraftJobs()
      }
    }
  )

  onMounted(() => {
    loadSystemSettings()
    refreshConversationHistory()
    attachmentFlow.resumePendingAiAttachmentAssociationJobs()
    expenseFlow.resumePendingLinkedReimbursementDraftJobs()
    document.addEventListener('click', handleWorkbenchDatePickerOutside)
  })

  onBeforeUnmount(() => {
    document.removeEventListener('click', handleWorkbenchDatePickerOutside)
  })

  return {
    activeConversationTitle,
    aiModeActionItems,
    aiModeInputLockMessage,
    applicationPreviewEditor,
    applicationSubmitConfirmOpen,
    assistantInputRef,
    assistantDraft,
    canShowInlineSuggestedActions: applicationFlow.canShowInlineSuggestedActions,
    canSubmitAiModePrompt,
    cancelDeleteConversation: () => sessionCommands.cancelDeleteConversation(deleteDialogOpen),
    cancelInlineApplicationSubmitConfirm: applicationFlow.cancelInlineApplicationSubmitConfirm,
    clearWorkbenchDateSelection,
    commitInlineApplicationPreviewEditor: applicationFlow.commitInlineApplicationPreviewEditor,
    confirmDeleteConversation: () => sessionCommands.confirmDeleteConversation(deleteDialogOpen),
    confirmInlineApplicationSubmit: applicationFlow.confirmInlineApplicationSubmit,
    conversationMessages,
    conversationScrollRef,
    conversationStarted,
    deleteDialogOpen,
    displayModelName,
    displayUserName,
    fileInputRef,
    handleAiAnswerMarkdownClick,
    handleAiModeFilesChange: filesFlow.handleAiModeFilesChange,
    handleInlineApplicationPreviewEditorKeydown: applicationFlow.handleInlineApplicationPreviewEditorKeydown,
    handleInlineConversationScroll,
    handleInlineSuggestedAction: actionRouter.handleInlineSuggestedAction,
    handleVoiceInput,
    hasInlineAttachmentOcrDetails,
    hasInlineThinking,
    isAiModeInputLocked,
    isApplicationPreviewEditing: applicationFlow.isApplicationPreviewEditing,
    isApplicationPreviewEstimatePending: applicationFlow.isApplicationPreviewEstimatePending,
    isInlineAttachmentOcrExpanded,
    isInlineSuggestedActionDisabled: applicationFlow.isInlineSuggestedActionDisabled,
    isInlineThinkingExpanded,
    markInlineMessageFeedback: messageActions.markInlineMessageFeedback,
    modelSelectorTitle,
    openApplicationPreviewEditor: applicationFlow.openApplicationPreviewEditor,
    quoteInlineMessage: messageActions.quoteInlineMessage,
    regenerateLastReply,
    removeAiModeFile: filesFlow.removeAiModeFile,
    removeWorkbenchDateTag,
    renderInlineConversationHtml,
    requestDeleteCurrentConversation: () => sessionCommands.requestDeleteCurrentConversation(deleteDialogOpen),
    resolveApplicationPreviewEditorOptions: applicationFlow.resolveApplicationPreviewEditorOptions,
    resolveInlineApplicationPreviewEditorControl: applicationFlow.resolveInlineApplicationPreviewEditorControl,
    resolveInlineApplicationPreviewEditorDateMax: applicationFlow.resolveInlineApplicationPreviewEditorDateMax,
    resolveInlineApplicationPreviewEditorDateMin: applicationFlow.resolveInlineApplicationPreviewEditorDateMin,
    resolveInlineApplicationPreviewMissingFields: applicationFlow.resolveInlineApplicationPreviewMissingFields,
    resolveInlineApplicationPreviewRows: applicationFlow.resolveInlineApplicationPreviewRows,
    resolveInlineAttachmentOcrDocuments,
    resolveInlineAttachmentOcrFileCount,
    resolveInlineThinkingEvents,
    runAiModeAction,
    scrollInlineConversationToTop,
    ...filePreview,
    sending,
    setAssistantInputRef,
    setWorkbenchDateMode,
    submitAiModePrompt,
    toggleInlineAttachmentOcrDetails,
    toggleInlineThinking,
    toggleWorkbenchDatePicker,
    triggerAiModeFileUpload: filesFlow.triggerAiModeFileUpload,
    workbenchCanApplyDateSelection,
    workbenchDateMode,
    workbenchDatePickerOpen,
    workbenchDateTagLabel,
    workbenchRangeEndDate,
    workbenchRangeStartDate,
    workbenchSingleDate,
    applyWorkbenchDateSelection,
    buildInlineApplicationPreviewFooterText: applicationFlow.buildInlineApplicationPreviewFooterText,
    copyInlineMessage: messageActions.copyInlineMessage,
    formatMessageTime,
    handleWorkbenchDateInputChange
  }
}
