import { resolveAssistantScopeGuard } from '../../utils/assistantSessionScope.js'
import { fetchReceiptFolderItems } from '../../services/receiptFolder.js'
import {
  handleBudgetCompileReportSubmit,
  shouldUseBudgetCompileReport
} from './budgetAssistantReportModel.js'
import { STEWARD_ASSISTANT_NAME } from './travelReimbursementSubmitConstants.js'
import { createStewardDelegationHelpers } from './travelReimbursementSubmitStewardDelegation.js'
import { createSubmitAttachmentAssociationFlow } from './travelReimbursementSubmitAttachmentFlow.js'
import { createSubmitApplicationPreviewHelpers } from './travelReimbursementSubmitApplicationPreview.js'
import { handleLocalApplicationPreviewFlow } from './travelReimbursementSubmitLocalPreviewFlow.js'
import { handleDraftAssociationPreflight } from './travelReimbursementSubmitDraftPreflight.js'
import { handleSubmitRecognitionFlow } from './travelReimbursementSubmitRecognitionFlow.js'
import {
  buildOperationFeedbackState,
  resolveAssistantResultText
} from './travelReimbursementSubmitResponseModel.js'
import {
  pushReimbursementAssociationPromptMessage
} from './travelReimbursementAssociationGateModel.js'

export function useTravelReimbursementSubmitComposer(ctx) {
  const {
    MAX_ATTACHMENTS,
    activeReviewPayload,
    activeSessionType,
    adjustComposerTextareaHeight,
    attachedFiles,
    buildAgentInsight,
    buildClientTimeContext,
    buildComposerBusinessTimeContext,
    buildComposerFilePreviews,
    buildDraftAssociationQueryPayload,
    buildErrorInsight,
    buildExpenseIntentConfirmationActions,
    buildExpenseIntentConfirmationMessage,
    buildExpenseSceneSelectionActions,
    buildExpenseSceneSelectionMessage,
    buildMessageMeta,
    buildOcrDocumentsFromReviewPayload,
    buildOcrSummaryFromDocuments,
    buildReviewFormContextFromPayload,
    clearAttachedFiles,
    clearFlowSimulationTimers,
    completeFlowResult,
    completeFlowStep,
    composerBusinessTimeDraftTouched,
    composerBusinessTimeTags,
    composerDraft,
    composerUploadIntent,
    conversationId,
    createMessage,
    currentInsight,
    currentUser,
    draftClaimId,
    emitDraftSaved,
    emitOperationCompleted,
    emitRequestUpdated,
    extractReviewAttachmentNames,
    failCurrentFlowStep,
    fetchExpenseClaims,
    fileInputRef,
    flowRunId,
    insightPanelCollapsed,
    isKnowledgeSession,
    linkedRequest,
    mergeBusinessTimeIntoExtraContext,
    mergeFilePreviews,
    mergeFilesWithLimit,
    mergeUploadAttachmentNames,
    mergeUploadOcrDocuments,
    messages,
    nextTick,
    normalizeExpenseQueryPayload,
    persistSessionState,
    props,
    registerApplicationPreviewDecision,
    recognizeOcrFiles,
    refreshCurrentUserFromBackend,
    refreshFlowRunDetail,
    rememberFilePreviews,
    replaceMessage,
    resolveComposerDisplaySubmitText,
    resetFlowRun,
    resolveComposerSubmitText,
    reviewInlineForm,
    runOrchestrator,
    scrollToBottom,
    sessionSwitchBusy,
    shouldRequestExpenseIntentConfirmation,
    shouldRequestExpenseSceneSelection,
    startExpenseClaimDraftFlowStep,
    startExpenseIntentConfirmationFlowPreview,
    startExpenseSceneSelectionFlowPreview,
    startFlowStep,
    startSemanticFlowPreview,
    submitting,
    syncComposerFilesToDraft,
    toast
  } = ctx

  const {
    buildStewardApplicationPreviewMessage,
    buildStewardApplicationPreviewSuggestedActions,
    buildStewardDelegatedPlan,
    buildStewardSlotDecisionMessage,
    buildStewardSlotDecisionSuggestedActions,
    fetchStewardApplicationSlotDecision,
    isStewardDelegatedRun,
    resetStewardDelegatedInsightState,
    shouldPauseStewardApplicationPreview,
    typeStewardDelegatedMessage
  } = createStewardDelegationHelpers({
    currentInsight,
    insightPanelCollapsed,
    messages,
    nextTick,
    persistSessionState,
    resetFlowRun,
    scrollToBottom
  })

  const {
    confirmPendingAttachmentAssociation,
    createPendingAttachmentAssociationId,
    emitSavedDraftRefresh,
    normalizeRecognizedAttachmentData,
    pendingAttachmentAssociations,
    promptUnlinkedReceiptFolderIfNeeded,
    resolveReviewPanelScope
  } = createSubmitAttachmentAssociationFlow({
    activeReviewPayload,
    buildReviewFormContextFromPayload,
    createMessage,
    draftClaimId,
    emitDraftSaved,
    fetchReceiptFolderItems,
    isKnowledgeSession,
    messages,
    nextTick,
    persistSessionState,
    resetFlowRun,
    reviewInlineForm,
    scrollToBottom,
    sessionSwitchBusy,
    submitComposer,
    submitting,
    toast
  })

  const {
    buildApplicationPreviewWithModelReview,
    buildBackendMessage,
    resolveDetailScopedClaimId
  } = createSubmitApplicationPreviewHelpers({
    activeSessionType,
    currentUser,
    isKnowledgeSession,
    linkedRequest,
    props,
    refreshCurrentUserFromBackend
  })

    async function submitComposer(options = {}) {
      if (submitting.value || sessionSwitchBusy.value) return null

      const rawText = resolveComposerSubmitText(options.rawText).trim()
      const systemGenerated = Boolean(options.systemGenerated)
      const appendToCurrentFlow = Boolean(options.appendToCurrentFlow)
      const effectiveSessionType = String(options.sessionTypeOverride || activeSessionType.value || '').trim()
      const stewardDelegated = isStewardDelegatedRun(options)
      const effectiveIsKnowledgeSession = effectiveSessionType === 'knowledge'
      const normalizedFiles = effectiveIsKnowledgeSession ? [] : Array.from(options.files ?? attachedFiles.value)
      const fileMergeResult = mergeFilesWithLimit([], normalizedFiles, MAX_ATTACHMENTS)
      const files = fileMergeResult.files
      const detailScopedClaimId = resolveDetailScopedClaimId()
      const detailScopedUpload = Boolean(detailScopedClaimId && files.length)
      if (detailScopedClaimId) {
        draftClaimId.value = detailScopedClaimId
      }
      const resolvedUploadDisposition =
        String(options.uploadDisposition || '').trim() ||
        (composerUploadIntent.value === 'continue_existing' ? 'continue_existing' : '') ||
        (detailScopedUpload ? 'continue_existing' : '')
      if (fileMergeResult.overflowCount > 0) {
        toast(`一次最多上传 ${MAX_ATTACHMENTS} 份附件，已保留前 ${MAX_ATTACHMENTS} 份。`)
      }
      if (!rawText && !files.length) return
      const fileNames = files.map((file) => file.name)

      const optionExtraContext = options.extraContext && typeof options.extraContext === 'object'
        ? { ...options.extraContext }
        : {}
      const detailScopedClaimNo = String(
        linkedRequest.value?.documentNo ||
          linkedRequest.value?.id ||
          ''
      ).trim()
      const initialExtraContext = detailScopedClaimId
        ? {
            ...optionExtraContext,
            draft_claim_id: detailScopedClaimId,
            selected_claim_id: detailScopedClaimId,
            selected_claim_no: detailScopedClaimNo,
            detail_scope_claim_id: detailScopedClaimId
          }
        : optionExtraContext
      const selectedBusinessTimeContext = effectiveIsKnowledgeSession ? null : buildComposerBusinessTimeContext()
      const extraContext = effectiveIsKnowledgeSession
        ? initialExtraContext
        : mergeBusinessTimeIntoExtraContext(initialExtraContext, selectedBusinessTimeContext)
      const reviewAction = String(extraContext.review_action || '').trim()
      const feedbackOperationType = String(options.feedbackOperationType || '').trim()
      const isApplicationSubmitOperation = feedbackOperationType === 'submit_application'
      const attachmentAssociationConfirmed = Boolean(
        options.associationConfirmed ||
          extraContext.attachment_association_confirmed ||
          reviewAction === 'link_to_existing_draft' ||
          detailScopedUpload
      )
      const hasSelectedExpenseType = Boolean(
        extraContext.expense_scene_selection ||
          String(extraContext.review_form_values?.expense_type || extraContext.review_form_values?.reimbursement_type || '').trim()
      )
      const hasConfirmedExpenseIntent = Boolean(extraContext.expense_intent_confirmed)
      const waitForExpenseIntentConfirmation = !stewardDelegated && shouldRequestExpenseIntentConfirmation(rawText, {
        sessionType: effectiveSessionType,
        attachmentCount: files.length,
        reviewAction,
        hasSelectedExpenseType,
        hasConfirmedExpenseIntent
      })
      const waitForExpenseSceneSelection = !stewardDelegated && !waitForExpenseIntentConfirmation && shouldRequestExpenseSceneSelection(rawText, {
        sessionType: effectiveSessionType,
        attachmentCount: files.length,
        reviewAction,
        hasSelectedExpenseType
      })
      const reviewAttachmentNames = extractReviewAttachmentNames(activeReviewPayload.value)
      const userText =
        String(options.userText || '').trim() ||
        resolveComposerDisplaySubmitText(rawText) ||
        rawText ||
        (effectiveIsKnowledgeSession
          ? `我上传了 ${fileNames.length} 份附件，请帮我回答相关财务问题。`
          : resolvedUploadDisposition === 'continue_existing'
            ? `继续上传 ${fileNames.length} 份票据，并归集到当前单据。`
            : resolvedUploadDisposition === 'new_document'
              ? `新上传 ${fileNames.length} 份票据，请单独建立报销单。`
              : `我上传了 ${fileNames.length} 份票据，请帮我识别并整理报销建议。`)

      if (!stewardDelegated && shouldUseBudgetCompileReport(rawText, {
        sessionType: effectiveSessionType,
        entrySource: props.entrySource,
        budgetContext: props.initialBudgetContext
      }) && !reviewAction) {
        return handleBudgetCompileReportSubmit({
          adjustComposerTextareaHeight,
          clearAttachedFiles,
          completeFlowStep,
          composerBusinessTimeDraftTouched,
          composerBusinessTimeTags,
          composerDraft,
          createMessage,
          currentUser,
          fileInputRef,
          fileNames,
          messages,
          nextTick,
          options,
          persistSessionState,
          rawText,
          replaceMessage,
          resetFlowRun,
          refreshCurrentUserFromBackend,
          budgetContext: props.initialBudgetContext,
          scrollToBottom,
          startFlowStep,
          submitting,
          userText
        })
      }

      const scopeGuard = resolveAssistantScopeGuard(rawText, effectiveSessionType, {
        attachmentCount: files.length,
        hasActiveReviewPayload: Boolean(activeReviewPayload.value),
        reviewAction
      })
      if (scopeGuard && !systemGenerated && !reviewAction && !options.skipScopeGuard) {
        if (!options.skipUserMessage) {
          messages.value.push(createMessage('user', userText, fileNames))
        }
        messages.value.push(createMessage('assistant', scopeGuard.text, [], {
          meta: scopeGuard.meta,
          suggestedActions: scopeGuard.suggestedActions
        }))
        composerDraft.value = ''
        composerBusinessTimeTags.value = []
        composerBusinessTimeDraftTouched.value = false
        nextTick(() => {
          adjustComposerTextareaHeight()
          scrollToBottom()
        })
        persistSessionState()
        return null
      }

      const localPreviewResult = await handleLocalApplicationPreviewFlow({
        adjustComposerTextareaHeight,
        buildApplicationPreviewWithModelReview,
        buildStewardApplicationPreviewMessage,
        buildStewardApplicationPreviewSuggestedActions,
        buildStewardDelegatedPlan,
        buildStewardSlotDecisionMessage,
        buildStewardSlotDecisionSuggestedActions,
        clearAttachedFiles,
        completeFlowStep,
        composerBusinessTimeDraftTouched,
        composerBusinessTimeTags,
        composerDraft,
        createMessage,
        effectiveSessionType,
        fetchExpenseClaims,
        fetchStewardApplicationSlotDecision,
        fileInputRef,
        fileNames,
        files,
        messages,
        nextTick,
        options,
        persistSessionState,
        rawText,
        registerApplicationPreviewDecision,
        replaceMessage,
        resetFlowRun,
        resetStewardDelegatedInsightState,
        reviewAction,
        scrollToBottom,
        selectedBusinessTimeContext,
        shouldPauseStewardApplicationPreview,
        startFlowStep,
        stewardDelegated,
        submitting,
        systemGenerated,
        typeStewardDelegatedMessage,
        userText
      })
      if (localPreviewResult.handled) {
        return localPreviewResult.value
      }


      if (!stewardDelegated && await promptUnlinkedReceiptFolderIfNeeded({
        detailScopedClaimId,
        files,
        fileNames,
        options,
        rawText,
        resolvedUploadDisposition,
        reviewAction,
        systemGenerated,
        userText
      })) {
        return null
      }

      const draftAssociationPreflight = await handleDraftAssociationPreflight({
        activeReviewPayload,
        adjustComposerTextareaHeight,
        buildComposerFilePreviews,
        buildDraftAssociationQueryPayload,
        createPendingAttachmentAssociationId,
        composerBusinessTimeDraftTouched,
        composerBusinessTimeTags,
        composerDraft,
        createMessage,
        detailScopedClaimId,
        draftClaimId,
        effectiveIsKnowledgeSession,
        extraContext,
        fetchExpenseClaims,
        fileNames,
        files,
        messages,
        nextTick,
        options,
        pendingAttachmentAssociations,
        persistSessionState,
        resetFlowRun,
        resolvedUploadDisposition,
        reviewAction,
        scrollToBottom,
        stewardDelegated,
        toast,
        userText
      })
      if (draftAssociationPreflight.handled) {
        return draftAssociationPreflight.value
      }


      if (stewardDelegated) {
        resetStewardDelegatedInsightState()
      } else if (!appendToCurrentFlow) {
        resetFlowRun()
      } else {
        clearFlowSimulationTimers()
      }
      if (!stewardDelegated && isApplicationSubmitOperation) {
        startFlowStep('application-submit-success', {
          title: '申请单提交成功',
          tool: 'ApplicationSubmit',
          detail: '正在提交费用申请...'
        })
      } else if (!stewardDelegated && rawText && !reviewAction) {
        startFlowStep('intent', '正在识别业务意图...')
        if (waitForExpenseIntentConfirmation) {
          startExpenseIntentConfirmationFlowPreview(rawText)
        } else if (waitForExpenseSceneSelection) {
          startExpenseSceneSelectionFlowPreview(rawText)
        } else {
          startSemanticFlowPreview(rawText, { attachmentCount: files.length })
        }
      }

      const filePreviews = buildComposerFilePreviews(files)
      rememberFilePreviews(filePreviews)

      // 只有在非静默模式下才添加用户消息
      if (!options.skipUserMessage) {
        messages.value.push(createMessage('user', userText, fileNames))
      }

      if (waitForExpenseIntentConfirmation) {
        messages.value.push(createMessage('assistant', buildExpenseIntentConfirmationMessage(rawText), [], {
          meta: ['等待确认意图'],
          suggestedActions: buildExpenseIntentConfirmationActions(rawText)
        }))
        composerDraft.value = ''
        composerBusinessTimeTags.value = []
        composerBusinessTimeDraftTouched.value = false
        clearAttachedFiles()
        if (fileInputRef.value) {
          fileInputRef.value.value = ''
        }
        nextTick(() => {
          adjustComposerTextareaHeight()
          scrollToBottom()
        })
        return null
      }

      if (waitForExpenseSceneSelection) {
        await pushReimbursementAssociationPromptMessage({
          rawText,
          createMessage,
          messages,
          nextTick,
          scrollToBottom,
          persistSessionState,
          fetchExpenseClaims,
          currentUser
        })
        composerDraft.value = ''
        composerBusinessTimeTags.value = []
        composerBusinessTimeDraftTouched.value = false
        clearAttachedFiles()
        if (fileInputRef.value) {
          fileInputRef.value.value = ''
        }
        nextTick(() => {
          adjustComposerTextareaHeight()
          scrollToBottom()
        })
        return null
      }

      const pendingMessage = createMessage(
        'assistant',
        stewardDelegated ? '' : options.pendingText || (
          effectiveIsKnowledgeSession
            ? '正在整理财务知识答案...'
            : effectiveSessionType === 'application'
              ? '正在识别申请信息并查询交通票价...'
              : effectiveSessionType === 'approval'
                ? '正在查询审核上下文并整理风险提示...'
                : '正在识别并整理右侧核对信息...'
        ),
        [],
        stewardDelegated
          ? {
              assistantName: STEWARD_ASSISTANT_NAME,
              meta: [STEWARD_ASSISTANT_NAME, '思考中'],
              stewardContinuation: options.stewardContinuation || null,
              stewardPlan: buildStewardDelegatedPlan(options.stewardContinuation || null, [], 'streaming')
            }
          : {
              meta: ['处理中']
            }
      )
      messages.value.push(pendingMessage)

      composerDraft.value = ''
      composerBusinessTimeTags.value = []
      composerBusinessTimeDraftTouched.value = false
      clearAttachedFiles()
      if (fileInputRef.value) {
        fileInputRef.value.value = ''
      }
      nextTick(adjustComposerTextareaHeight)

      submitting.value = true
      nextTick(scrollToBottom)

      let responsePayload = null

      try {
        const user = currentUser.value || {}
        const recognitionFlow = await handleSubmitRecognitionFlow({
          activeReviewPayload,
          attachmentAssociationConfirmed,
          buildOcrDocumentsFromReviewPayload,
          buildOcrSummaryFromDocuments,
          buildReviewFormContextFromPayload,
          completeFlowStep,
          createMessage,
          createPendingAttachmentAssociationId,
          draftClaimId,
          extraContext,
          fileNames,
          filePreviews,
          files,
          mergeUploadAttachmentNames,
          mergeUploadOcrDocuments,
          nextTick,
          normalizeRecognizedAttachmentData: () => normalizeRecognizedAttachmentData(options.recognizedAttachmentData),
          pendingAttachmentAssociations,
          pendingMessage,
          persistSessionState,
          recognizeOcrFiles,
          rememberFilePreviews,
          replaceMessage,
          resolvedUploadDisposition,
          reviewAttachmentNames,
          reviewInlineForm,
          scrollToBottom,
          startFlowStep,
          stewardDelegated
        })
        if (recognitionFlow.handled) {
          return recognitionFlow.value
        }
        const {
          effectiveFileNames,
          effectiveOcrDocuments,
          effectiveOcrSummary,
          ocrFilePreviews
        } = recognitionFlow

        if (!isApplicationSubmitOperation && !stewardDelegated) {
          startExpenseClaimDraftFlowStep(String(extraContext.review_action || '').trim(), {
            attachmentCount: effectiveFileNames.length,
            waitForSceneSelection: waitForExpenseSceneSelection
          })
        }

        const backendMessage = buildBackendMessage(
          rawText,
          effectiveFileNames,
          effectiveOcrSummary,
          effectiveSessionType
        )
        const orchestratorOptions = effectiveIsKnowledgeSession
          ? {
              timeoutMs: 75000,
              timeoutMessage: '知识问答仍在检索整理，已停止等待。请稍后重试，或补充制度名称、费用类型等限定条件。'
            }
          : {
              timeoutMs: 120000,
              timeoutMessage: '票据归集处理超时，当前仍停留在原草稿，请稍后重试或重新选择附件。'
            }

        const payload = await runOrchestrator(
          {
            source: 'user_message',
            user_id: user.username || user.name || 'anonymous',
            conversation_id: conversationId.value || null,
            message: backendMessage,
            context_json: {
              role_codes: Array.isArray(user.roleCodes) ? user.roleCodes : [],
              is_admin: Boolean(user.isAdmin),
              name: user.name || '',
              role: user.role || '',
              department: user.department || user.departmentName || '',
              department_name: user.department || user.departmentName || '',
              position: user.position || '',
              employee_position: user.position || user.employeePosition || user.employee_position || '',
              employeePosition: user.position || user.employeePosition || user.employee_position || '',
              grade: user.grade || user.employeeGrade || user.employee_grade || '',
              employee_grade: user.grade || user.employeeGrade || user.employee_grade || '',
              employeeGrade: user.grade || user.employeeGrade || user.employee_grade || '',
              employee_no: user.employeeNo || user.employee_no || '',
              employeeNo: user.employeeNo || user.employee_no || '',
              manager_name: user.managerName || user.manager_name || '',
              managerName: user.managerName || user.manager_name || '',
              direct_manager_name: user.managerName || user.manager_name || user.directManagerName || user.direct_manager_name || '',
              directManagerName: user.managerName || user.manager_name || user.directManagerName || user.direct_manager_name || '',
              employee_location: user.location || '',
              cost_center: user.costCenter || user.cost_center || '',
              finance_owner_name: user.financeOwnerName || user.finance_owner_name || '',
              employee_risk_profile: user.riskProfile && typeof user.riskProfile === 'object' ? user.riskProfile : {},
              ...buildClientTimeContext(),
              session_type: effectiveSessionType,
              entry_source: props.entrySource,
              user_input_text: systemGenerated ? '' : rawText,
              attachment_names: effectiveFileNames,
              attachment_count: effectiveFileNames.length,
              draft_claim_id: effectiveIsKnowledgeSession ? undefined : draftClaimId.value || undefined,
              ocr_summary: effectiveOcrSummary,
              ocr_documents: effectiveOcrDocuments,
              ...(linkedRequest.value && !effectiveIsKnowledgeSession ? { request_context: linkedRequest.value } : {}),
              ...extraContext
            }
          },
          orchestratorOptions
        )
        responsePayload = payload
        flowRunId.value = stewardDelegated ? '' : String(payload?.run_id || '').trim()
        let flowRunDetail = null
        if (flowRunId.value) {
          flowRunDetail = await refreshFlowRunDetail()
        }

        conversationId.value = String(payload?.conversation_id || '').trim() || conversationId.value
        draftClaimId.value =
          effectiveIsKnowledgeSession
            ? ''
            : String(payload?.result?.draft_payload?.claim_id || '').trim() || draftClaimId.value

        const reviewActionResult = String(extraContext.review_action || '').trim()
        const resultClaimNo = String(payload?.result?.draft_payload?.claim_no || '').trim()
        const fallbackAnswer = reviewActionResult === 'link_to_existing_draft'
          ? (resultClaimNo ? `已将本次上传的票据关联到草稿 ${resultClaimNo}。` : '已将本次上传的票据关联到现有草稿。')
          : '智能体已完成处理。'
        const resolvedDraftClaimId = String(payload?.result?.draft_payload?.claim_id || draftClaimId.value || '').trim()
        let attachmentSyncCompleted = false
        const persistComposerFilesToDraft = async () => {
          try {
            const syncResult = await syncComposerFilesToDraft(resolvedDraftClaimId, files)
            persistSessionState()
            if (detailScopedUpload) {
              emitRequestUpdated?.({
                claimId: resolvedDraftClaimId,
                source: 'detail-smart-entry-attachment-sync',
                uploadedCount: Number(syncResult?.uploadedCount || 0),
                skippedCount: Number(syncResult?.skippedCount || 0)
              })
            }
            return syncResult
          } catch (error) {
            console.warn('Failed to persist composer attachments to draft claim:', error)
            toast(error?.message || '票据已归集到草稿，但附件原件保存失败，请在单据详情中重新上传。')
            return null
          }
        }
        if (
          reviewActionResult === 'link_to_existing_draft' &&
          !effectiveIsKnowledgeSession &&
          resolvedDraftClaimId &&
          files.length
        ) {
          await persistComposerFilesToDraft()
          attachmentSyncCompleted = true
        }
        const operationFeedbackContext = String(payload?.status || '').trim() === 'succeeded'
          ? emitOperationCompleted?.(payload, {
              operationType: feedbackOperationType || reviewActionResult || (files.length ? 'attachment_review' : 'assistant_round')
            })
          : null
        const assistantMessage = createMessage('assistant', resolveAssistantResultText(payload, fallbackAnswer), [], {
          meta: buildMessageMeta(payload, effectiveFileNames),
          citations: Array.isArray(payload?.result?.citations) ? payload.result.citations : [],
          suggestedActions: Array.isArray(payload?.result?.suggested_actions)
            ? payload.result.suggested_actions
            : [],
          queryPayload: normalizeExpenseQueryPayload(payload?.result?.query_payload),
          draftPayload: payload?.result?.draft_payload || null,
          reviewPayload: payload?.result?.review_payload || null,
          reviewPanelScope: stewardDelegated
            ? ''
            : resolveReviewPanelScope({
                reviewPayload: payload?.result?.review_payload || null,
                reviewAction: reviewActionResult,
                fileCount: files.length,
                rawText
              }),
          riskFlags: Array.isArray(payload?.result?.risk_flags) ? payload.result.risk_flags : [],
          operationFeedback: buildOperationFeedbackState(operationFeedbackContext),
          assistantName: stewardDelegated ? STEWARD_ASSISTANT_NAME : undefined,
          stewardContinuation: options.stewardContinuation || null
        })
        if (stewardDelegated) {
          await typeStewardDelegatedMessage(
            pendingMessage.id,
            assistantMessage.text,
            {
              ...assistantMessage,
              id: pendingMessage.id,
              reviewPanelScope: ''
            },
            {
              sessionType: effectiveSessionType,
              rawText,
              fileNames: effectiveFileNames,
              stewardContinuation: options.stewardContinuation || null
            }
          )
          resetStewardDelegatedInsightState()
        } else {
          replaceMessage(pendingMessage.id, assistantMessage)
          const nextInsight = buildAgentInsight(
            payload,
            effectiveFileNames,
            mergeFilePreviews(filePreviews, ocrFilePreviews)
          )
          if (nextInsight.agent) {
            nextInsight.agent.reviewPanelScope = assistantMessage.reviewPanelScope
          }
          currentInsight.value = nextInsight
          completeFlowResult(payload, flowRunDetail)
        }
        if (['save_draft', 'link_to_existing_draft', 'create_new_claim_from_documents'].includes(reviewActionResult)) {
          emitSavedDraftRefresh(payload?.result?.draft_payload || null)
        }
        persistSessionState()
        nextTick(scrollToBottom)
        if (!effectiveIsKnowledgeSession && resolvedDraftClaimId && files.length) {
          if (!attachmentSyncCompleted) {
            const persistTask = persistComposerFilesToDraft()
            if (detailScopedUpload) {
              await persistTask
            } else {
              void persistTask
            }
          }
        }
      } catch (error) {
        clearFlowSimulationTimers()
        if (!stewardDelegated) {
          failCurrentFlowStep(error)
        }
        replaceMessage(
          pendingMessage.id,
          createMessage(
            'assistant',
            error?.message || '无法连接后端 Orchestrator，请稍后重试。',
            [],
            stewardDelegated
              ? {
                  assistantName: STEWARD_ASSISTANT_NAME,
                  meta: [STEWARD_ASSISTANT_NAME, '调用失败'],
                  stewardContinuation: options.stewardContinuation || null
                }
              : {
                  meta: ['调用失败']
                }
          )
        )
        if (stewardDelegated) {
          resetStewardDelegatedInsightState()
        } else {
          currentInsight.value = buildErrorInsight(error, fileNames)
        }
        persistSessionState()
      } finally {
        submitting.value = false
        composerUploadIntent.value = ''
        nextTick(scrollToBottom)
      }

      return responsePayload
    }


  return {
    confirmPendingAttachmentAssociationInternal: confirmPendingAttachmentAssociation,
    submitComposerInternal: submitComposer
  }
}
