import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useLocation, useParams, useSearchParams } from 'react-router-dom'
import { Button } from '@heroui/react'
import { motion } from 'framer-motion'
import { useScroll } from 'ahooks'
import styles from './Chat.module.less'
import { getLastQaRecordWorkflowContext, processApiResponse } from './helper'
import { ChatWelcome } from './components/ChatWelcome'
import { ChatItemUser } from './components/ChatItem/ChatItemUser'
import { ChatAnswerBox } from './components/ChatItem/ChatAnswerBox'
import { trimSpacesOnly } from './components/ChatItem/markdownFormatter'
import { ChatEditor } from '@/components/ChatEditor'
import type { ChatRecord } from '@/types/chat'
import { fetchSessionConversationId, fetchUserQaRecordPage } from '@/api/conversation'
import { fetchCheckTokenApi, fetchStreamResponse } from '@/api/chat'
import { clearCurrentToolId, clearShouldSendQuestion, exitBusinessInsightSubWorkflow, fetchConversations, setBusinessInsightMainWorkflow, setBusinessInsightPendingQuestion, setBusinessInsightSubWorkflow, setCurrentToolId } from '@/store/conversationSlice'
import { getUserRolesForApi, safeSessionStorageGetItem, waitForToken } from '@/lib/utils'
import { findGeneralToolRow, findToolRowBySessionToolId, readToolListFromSessionStorage } from '@/lib/toolRoleRecordTypes'
import { getWorkflowToolIdAndRecordTypeForSubmit, setWorkflowLastToolPair } from '@/lib/workflowToolParams'
import type { RootState } from '@/store'
import { useAppDispatch, useAppSelector } from '@/store/hook'
import ScrollBtoIcon from '@/assets/svg/scrollBto.svg?react'
import { setIsAsking } from '@/store/chatSlice'
import SdreamLoading from '@/components/SdreamLoading'

function makeLocalGroupId(prefix: string) {
  try {
    // modern browsers
    return `${prefix}-${crypto.randomUUID()}`
  }
  catch {
    return `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2)}`
  }
}

export const Chat: React.FC = () => {
  const { id } = useParams<{ id: string }>()
  const location = useLocation()
  const [searchParams, setSearchParams] = useSearchParams()
  // 优先从 URL 查询参数读取 toolId（刷新后仍能保留），其次从 location.state 读取
  const rawToolIdFromUrl = searchParams.get('toolId')
  // 只有在非 SPA 导航（location.state 不存在）且链接携带 toolId 时才清空，避免影响站内点击历史记录
  const shouldForceClearUrlToolId = !location.state && Boolean(rawToolIdFromUrl)
  const toolIdFromUrl = shouldForceClearUrlToolId ? null : rawToolIdFromUrl
  // 添加调试日志，查看 location.state 的实际值
  const toolIdFromState = (location.state as { toolId?: string | null } | null)?.toolId
  // 优先使用 URL 中的 toolId，其次使用 state 中的 toolId
  const initialToolId = toolIdFromUrl !== null ? toolIdFromUrl : toolIdFromState
  const [isLoading, setIsLoading] = useState(false)
  const [allItems, setAllItems] = useState<ChatRecord[]>([])
  const dispatch = useAppDispatch()
  const { shouldSendQuestion, currentToolId, conversations, businessInsightWorkflow } = useAppSelector((state: RootState) => state.conversation)
  const isAsking = useAppSelector((state: RootState) => state.chat.isAsking)
  // 标记历史记录是否已加载完成，用于确保自动发送问题在历史记录加载后执行
  const historyLoadedRef = useRef<{ conversationId: string | null }>({ conversationId: null })
  // 保存待发送的问题，用于在历史记录加载完成后发送
  const pendingQuestionRef = useRef<string | null>(null)
  const scrollableRef = useRef<HTMLDivElement | any>(null)
  const position = useScroll(scrollableRef)
  const currentIdRef = useRef<string | undefined>(id)
  const lastSentQuestionRef = useRef<string>('')
  const abortControllerRef = useRef<AbortController | null>(null)
  const [currentToolName, setCurrentToolName] = useState<string | undefined>(undefined)
  // 使用 ref 保存从 location.state 传递的 toolId，避免被异步操作覆盖
  const toolIdFromStateRef = useRef<string | null | undefined>(undefined)
  // 标记是否已通过 toolHistoryLoaded 事件加载数据，避免重复调用接口
  const toolHistoryLoadedRef = useRef<{ conversationId: string | null }>({ conversationId: null })
  // 标记是否已处理从收藏返回的逻辑，避免重复调用
  const fromCollectProcessedRef = useRef<boolean>(false)
  // 保存从收藏返回的标记，避免 location.state 被清除后丢失
  const fromCollectRef = useRef<boolean>(false)
  // 记录正在处理的 conversationId，避免重复调用
  const processingConversationIdRef = useRef<string | null>(null)
  /** 最近一次 query_user_qa_record_list 最后一条上的 workflow 字段，供自动提问透传 */
  const lastLoadedQaWorkflowContextRef = useRef<{
    recordType: string
    workFlowSessionId: string
    busiType?: string
  } | null>(null)
  // 标记是否为提质增效模式的自动调用（用于提取欢迎语）
  const isAutoSubmitQualityImprovementRef = useRef<boolean>(false)
  // 提质增效自动调用欢迎语候选（用于流结束后写入 sessionStorage）
  const autoWelcomeCandidateRef = useRef<string>('')
  const hasAutoWelcomeCandidateRef = useRef<boolean>(false)
  // 业务洞察工作流状态 ref（用于在流结束后访问最新状态）
  const businessInsightWorkflowRef = useRef<{
    mainWorkflowSessionId: string | null
    subWorkflowSessionId: string | null
    subWorkflowRecordType: string | null
    paramMap: Record<string, string>
    isInSubWorkflow: boolean
    pendingQuestion: string | null
  }>({
    mainWorkflowSessionId: null,
    subWorkflowSessionId: null,
    subWorkflowRecordType: null,
    paramMap: {},
    isInSubWorkflow: false,
    pendingQuestion: null,
  })
  /** 主工作流返回「进子」JSON 后，已发起空问题「开子」请求，等待本轮流结束写入子 session */
  const expectingSubWorkflowOpenRef = useRef(false)
  const pendingSubOpenRecordTypeRef = useRef<string | null>(null)
  const pendingSubQuestionRef = useRef<string | null>(null)

  // 当外部系统直接以 /chat/:id 链接进入（没有 location.state，且 URL 中也没有 toolId）时，
  // 视为一次新的会话入口：重置为制度活化，清除历史遗留的工具模式状态
  useEffect(() => {
    if (!location.state && !rawToolIdFromUrl) {
      dispatch(clearCurrentToolId())
      // sessionStorage.removeItem('currentToolId')
    }
  }, [location.state, rawToolIdFromUrl, dispatch])
  // 若链接中带有 toolId，进入页面后强制清空（避免沿用历史链接参数）
  useEffect(() => {
    if (!shouldForceClearUrlToolId)
      return

    // 1. 清除 Redux 中的 currentToolId
    dispatch(clearCurrentToolId())
    // 2. 清除 sessionStorage 中的 currentToolId
    // sessionStorage.removeItem('currentToolId')
    // 3. 清除 URL 中的 toolId 参数（如果存在）
    const currentUrl = new URL(window.location.href)
    if (currentUrl.searchParams.has('toolId')) {
      currentUrl.searchParams.delete('toolId')
      window.history.replaceState({}, '', currentUrl.toString())
    }
    // 4. 触发自定义事件，通知 ChatEditor 强制重置为制度活化
    window.dispatchEvent(new CustomEvent('forceResetToGeneralMode'))

    // 同步 react-router 的 searchParams 状态
    const newParams = new URLSearchParams(searchParams)
    newParams.delete('toolId')
    setSearchParams(newParams, { replace: true })
  }, [searchParams, setSearchParams, shouldForceClearUrlToolId, dispatch])
  // 调试用：展示当前页面链接与缓存中的 toolId
  const [debugInfo, setDebugInfo] = useState<{ href: string, sessionToolId: string | null }>({
    href: '',
    sessionToolId: null,
  })

  // 进入聊天页时，同步当前链接和缓存中的 toolId 到页面上展示
  useEffect(() => {
    try {
      const href = window.location.href
      const sessionToolId = sessionStorage.getItem('currentToolId')
      setDebugInfo({
        href,
        sessionToolId,
      })
    }
    catch (error) {
      console.error('同步页面链接与缓存信息失败:', error)
    }
  }, [])

  useEffect(() => {
    if (!debugInfo.href && !debugInfo.sessionToolId)
      return
    console.debug('[Chat] 当前链接 / 缓存 toolId:', debugInfo)
  }, [debugInfo])

  // 调试：观察 shouldSendQuestion 在对话页的变化
  useEffect(() => {
    console.log('[Chat] shouldSendQuestion changed 111111:', {
      conversationIdFromRoute: id,
      shouldSendQuestion,
      currentToolId,
      isLoading,
      allItemsLength: allItems.length,
    })
  }, [id, shouldSendQuestion, currentToolId, isLoading, allItems.length])

  // 历史记录点击时将 toolId 通过路由 state 传入，优先使用该值快速同步高亮
  useEffect(() => {
    // 保存从 location.state 传递的 toolId 到 ref
    toolIdFromStateRef.current = initialToolId
    if (typeof initialToolId === 'undefined')
      return
    if (initialToolId) {
      // 统一转换为字符串，确保类型一致（真实API可能返回数字，需要转换为字符串）
      const normalizedToolId = String(initialToolId)
      dispatch(setCurrentToolId(normalizedToolId))
    }
    else {
      dispatch(clearCurrentToolId())
    }
  }, [dispatch, initialToolId])

  // 同步业务洞察工作流状态到 ref
  useEffect(() => {
    businessInsightWorkflowRef.current = businessInsightWorkflow
  }, [businessInsightWorkflow])

  /** 处理正常stream的数据 */
  const handleStreamMesageData = (msg: any, question: string) => {
    setAllItems((prevItems) => {
      const newItems = [...prevItems] // 创建数组的浅拷贝
      const lastIndex = newItems.length - 1
      const isEmptyQuestion = !question.trim()
      // 提质增效自动欢迎语场景：空问题的流式回答应追加在历史记录之后，避免复用最后一条历史 AI 记录
      const shouldAlwaysAppendAi = isAutoSubmitQualityImprovementRef.current && isEmptyQuestion

      // 提质增效模式下，自动调用时收集首个有效 answer 作为欢迎语候选（按流式增量累积）
      if (isAutoSubmitQualityImprovementRef.current && isEmptyQuestion) {
        const chunkAnswer = msg?.content?.data?.answer
        if (typeof chunkAnswer === 'string') {
          // 仅对当前分片做基础清洗，避免重复累积整段答案导致内容重复
          let cleanedChunk = chunkAnswer.replace(/\([^)]*\)/g, '')
          cleanedChunk = cleanedChunk.replace(/\[参考文档(?:《[^》]*》\s*)+\]/g, '')
          cleanedChunk = trimSpacesOnly(cleanedChunk)
          if (cleanedChunk.trim()) {
            autoWelcomeCandidateRef.current = (autoWelcomeCandidateRef.current || '') + cleanedChunk
            hasAutoWelcomeCandidateRef.current = true
          }
        }
      }

      // 提质增效模式下，自动调用时第一个数据块作为欢迎语（兼容旧逻辑，仍保留对 system.welcomeText 的写入）
      if (isAutoSubmitQualityImprovementRef.current && isEmptyQuestion && msg.content.data.answer) {
        // 判断是否为第一个数据块（只有 system 记录或最后一个记录是 system）
        const isFirstChunk = newItems.length === 1 && newItems[0].role === 'system'

        if (isFirstChunk) {
          // 提取欢迎语并更新到 system 记录
          const welcomeText = msg.content.data.answer
          const systemIndex = newItems.findIndex(item => item.role === 'system')
          if (systemIndex >= 0) {
            newItems[systemIndex] = {
              ...newItems[systemIndex],
              welcomeText,
            } as ChatRecord
          }
          // 清除标记，后续数据块不再处理为欢迎语
          isAutoSubmitQualityImprovementRef.current = false
          return newItems
        }
      }

      // 如果是空问题且需要追加新的 AI 记录（历史末尾没有 AI，或提质增效自动欢迎语场景），则添加 AI 回答占位
      if (isEmptyQuestion && (lastIndex < 0 || newItems[lastIndex].role !== 'ai' || shouldAlwaysAppendAi)) {
        newItems.push({
          role: 'ai',
          groupId: makeLocalGroupId('ai'),
          answerList: [{ answer: '' }],
        } as ChatRecord)
      }

      const currentIndex = newItems.length - 1
      if (currentIndex >= 0 && newItems[currentIndex].role === 'ai') {
        // 创建最后一项的新对象，合并现有数据和新的 answer
        const existingAnswer = newItems[currentIndex].answerList?.[0] || {}
        const originalAnswer = (existingAnswer.answer || '') + (msg.content.data.answer ?? '\n')
        // 移除所有括号及其内容（但保留 Markdown 链接语法中的 ](...)）
        let filteredAnswer = originalAnswer.replace(/\([^)]*\)/g, (match, offset, str) => {
          return str[offset - 1] === ']' ? match : ''
        })
        // 去除 [参考文档《任意内容》 《任意内容》...] 格式的内容
        filteredAnswer = filteredAnswer.replace(/\[参考文档(?:《[^》]*》\s*)+\]/g, '')
        // 只移除空格和制表符，保留换行符（避免移除末尾的 \n\n）
        filteredAnswer = trimSpacesOnly(filteredAnswer)

        // 在流式响应过程中，忽略服务器返回的 endAnswerFlag，避免过早禁用输入框
        const { endAnswerFlag: _omitEndAnswerFlag, ...dataWithoutEndFlag } = msg.content.data || {}
        const chunkToolId = dataWithoutEndFlag.toolId != null ? String(dataWithoutEndFlag.toolId).trim() : ''
        const chunkRecordType = dataWithoutEndFlag.recordType != null ? String(dataWithoutEndFlag.recordType).trim() : ''
        if (chunkToolId && chunkRecordType)
          setWorkflowLastToolPair(chunkToolId, chunkRecordType)
        // 保留之前保存的 workFlowSessionId 和 recordId，避免被覆盖
        newItems[currentIndex] = {
          ...newItems[currentIndex],
          question: isEmptyQuestion ? undefined : question,
          answerList: [
            {
              ...existingAnswer,
              ...dataWithoutEndFlag,
              // 如果新的数据中没有 workFlowSessionId，保留之前的值
              workFlowSessionId: dataWithoutEndFlag.workFlowSessionId ?? existingAnswer.workFlowSessionId,
              // 如果新的数据中没有 recordId，保留之前的值
              recordId: dataWithoutEndFlag.recordId ?? existingAnswer.recordId,
              isShow: false,
              answer: filteredAnswer,
            },
          ],
        }
      }
      return newItems
    })
  }

  /** 处理超过最大条数的数据 */
  const handleChatMaxCount = (msg: any, question: string) => {
    setAllItems((prevItems) => {
      const newItems = [...prevItems] // 创建数组的浅拷贝
      const lastIndex = newItems.length - 1
      const isEmptyQuestion = !question.trim()

      // 如果是空问题且最后一项不是AI回答，需要添加AI回答
      if (isEmptyQuestion && (lastIndex < 0 || newItems[lastIndex].role !== 'ai')) {
        newItems.push({
          role: 'ai',
          groupId: makeLocalGroupId('ai'),
          answerList: [{ answer: '' }],
        } as ChatRecord)
      }

      const currentIndex = newItems.length - 1
      if (currentIndex >= 0 && newItems[currentIndex].role === 'ai') {
        // 创建最后一项的新对象，合并现有数据和新的 answer
        newItems[currentIndex] = {
          ...newItems[currentIndex],
          question: isEmptyQuestion ? undefined : question,
          answerList: [
            {
              ...msg.content.data,
              isShow: false,
              isChatMaxCount: true,
              endAnswerFlag: true,
              answer: '已达上限',
            },
          ],
        }
      }
      return newItems
    })
  }

  /** 提交问题 */
  const handleSubmitQuestion = async (
    question: string,
    productCode?: string,
    toolId?: string,
    extraParams?: { paramMap?: Record<string, string>, recordId?: string, recordType?: string, workFlowSessionId?: string, isReask?: boolean, busiType?: string },
    workFlowSessionId?: string,
    recordId?: string,
  ) => {
    // 优先读取缓存中的 toolId，再回退到传参或 Redux
    const sessionToolId = sessionStorage.getItem('currentToolId') ?? undefined
    const resolvedToolId = toolId ?? sessionToolId ?? currentToolId ?? undefined
    // 业务洞察等工作流参数：有主/子会话态时合并进 extra（不依赖写死 toolId）
    let workflowExtraParams = extraParams
    if (businessInsightWorkflowRef.current) {
      const workflowState = businessInsightWorkflowRef.current
      if (workflowState.isInSubWorkflow) {
        workflowExtraParams = {
          ...extraParams,
          recordType: workflowState.subWorkflowRecordType || undefined,
          workFlowSessionId: workflowState.subWorkflowSessionId || workFlowSessionId,
          paramMap: workflowState.paramMap,
        }
      }
      else if (workflowState.mainWorkflowSessionId) {
        workflowExtraParams = {
          ...extraParams,
          workFlowSessionId: workflowState.mainWorkflowSessionId,
        }
      }
    }
    // 空问题 + 显式传入 recordType/busiType（如工具入口 autoSubmit）时走自动欢迎语流式逻辑；
    // 已有主会话后的空问题（如「开子工作流」）不应走欢迎语分支
    const isEmptyQuestion = !question.trim()
    const isAutoToolEmptySubmit = isEmptyQuestion
      && Boolean(extraParams?.recordType && extraParams?.busiType)
      && !businessInsightWorkflowRef.current.mainWorkflowSessionId
    isAutoSubmitQualityImprovementRef.current = isAutoToolEmptySubmit
    if (isAutoSubmitQualityImprovementRef.current) {
      // 重置欢迎语候选
      autoWelcomeCandidateRef.current = ''
      hasAutoWelcomeCandidateRef.current = false
    }
    // 停止之前的请求
    if (abortControllerRef.current) {
      abortControllerRef.current.abort()
    }

    const isNew = allItems.length <= 1
    dispatch(setIsAsking(true))

    // 先展示用户气泡与 AI 占位，避免 check_token 失败时界面毫无反馈且流式接口未发出
    if (question.trim()) {
      setAllItems(prevItems => [
        ...prevItems,
        {
          role: 'user',
          groupId: makeLocalGroupId('user'),
          question,
        } as ChatRecord,
        {
          role: 'ai',
          groupId: makeLocalGroupId('ai'),
          answerList: [{ answer: '' }],
        } as ChatRecord,
      ])
    }

    // 检查 token：失败不阻断提问（流式请求仍带 X-Token，由服务端校验）
    try {
      await fetchCheckTokenApi()
    }
    catch (e) {
      console.warn('[Chat] check_token 失败，仍尝试发起流式提问:', e)
    }

    // 创建新的 AbortController
    abortControllerRef.current = new AbortController()

    let fetchUrl = `/conversation/api/conversation/mobile/v1/submit_question_stream`

    const viteOutputObj = import.meta.env.VITE_OUTPUT_OBJ || 'open'

    let proxy = ''
    if (viteOutputObj === 'open') {
      proxy = import.meta.env.MODE !== 'prod' ? '/api' : '/dev-sdream-api'
    }
 else {
      proxy = import.meta.env.MODE === 'dev' ? '/api' : '/dev-sdream-api'
    }

    fetchUrl = proxy + fetchUrl

    // 根据 toolId 添加相应的参数
    const requestBody: Record<string, any> = {
      question,
      conversationId: currentIdRef.current,
      stream: true,
      productCode,
      toolId: resolvedToolId ?? '',
    }

    // 如果是 workflow 提交，添加 paramMap、recordId 和 workFlowSessionId
    if (workflowExtraParams?.paramMap) {
      requestBody.paramMap = workflowExtraParams.paramMap
    }
    // 优先使用 workflowExtraParams 中的值，其次使用直接传递的参数
    if (workflowExtraParams?.recordId) {
      requestBody.recordId = workflowExtraParams.recordId
    }
    else if (recordId) {
      requestBody.recordId = recordId
    }

    // workFlowSessionId 的传递逻辑：
    // 1. 如果是重新问答（isReask === true），不传递 workFlowSessionId
    // 2. 提质增效等空问题自动调用：未显式传入 workFlowSessionId 时不传（欢迎语首轮）；若 extra/参数中已带历史最后一条的 session 则仍传递
    // 3. 优先使用 workflowExtraParams 中的值
    // 4. 其次使用直接传递的参数
    // 5. 若仍没有且非「无显式 session 的提质增效自动调用」，从会话历史中找到最后一个有 workFlowSessionId 的答案
    const isReask = workflowExtraParams?.isReask === true
    const isAutoQualityImprovement = isAutoSubmitQualityImprovementRef.current
    const explicitWorkFlowSessionId = workflowExtraParams?.workFlowSessionId || workFlowSessionId
    const shouldUseWorkflowSession = Boolean(resolvedToolId && String(resolvedToolId).trim() !== '')
    if (shouldUseWorkflowSession && !isReask) {
      let resolvedWorkflowSessionId: string | undefined
      if (explicitWorkFlowSessionId) {
        resolvedWorkflowSessionId = explicitWorkFlowSessionId
      }
      else if (!isAutoQualityImprovement) {
        for (let i = allItems.length - 1; i >= 0; i--) {
          const item = allItems[i]
          if (item.role === 'ai' && item.answerList?.[0]?.workFlowSessionId) {
            resolvedWorkflowSessionId = item.answerList[0].workFlowSessionId
            break
          }
        }
      }
      if (resolvedWorkflowSessionId) {
        requestBody.workFlowSessionId = resolvedWorkflowSessionId
      }
    }

    // 如果传入了 recordType，优先使用传入的值（workflow 提交场景）
    if (workflowExtraParams?.recordType) {
      requestBody.recordType = workflowExtraParams.recordType
      // 如果同时传入了 busiType，也使用传入的值
      if (workflowExtraParams?.busiType) {
        requestBody.busiType = workflowExtraParams.busiType
      }
    }
    // 制度活化：toolId 为空字符串或 undefined
    else if (!resolvedToolId || resolvedToolId === '') {
      requestBody.toolId = ''
      requestBody.busiType = '01'
      requestBody.recordType = '01'
    }
    else {
      const workflowPair = getWorkflowToolIdAndRecordTypeForSubmit()
      if (workflowPair?.toolId && workflowPair?.recordType) {
        requestBody.toolId = workflowPair.toolId
        requestBody.busiType = workflowExtraParams?.busiType ?? extraParams?.busiType ?? '01'
        requestBody.recordType = workflowPair.recordType
      }
      else {
        requestBody.toolId = resolvedToolId
        requestBody.busiType = '01'
        requestBody.recordType = '01'
      }
    }

    fetchStreamResponse(
      fetchUrl,
      requestBody,
      (msg) => {
        // 检查是否已被取消
        if (abortControllerRef.current?.signal.aborted) {
          return
        }

        // 处理错误
        if (msg?.type === 'ERROR') {
          // 出错时需要重置 isAsking 状态
          dispatch(setIsAsking(false))
          // 如果是 AbortError，不显示错误
          if (msg.content?.name === 'AbortError') {
            return
          }
          // 设置最后一条 AI 回答的 endAnswerFlag，用于停止打字效果
          setAllItems((prevItems) => {
            const newItems = [...prevItems]
            // 从后往前找到最后一个 AI 项
            for (let i = newItems.length - 1; i >= 0; i--) {
              if (newItems[i].role === 'ai' && newItems[i].answerList?.[0]) {
                const prevAnswer = newItems[i].answerList[0].answer
                newItems[i] = {
                  ...newItems[i],
                  answerList: [
                    {
                      ...newItems[i].answerList[0],
                      endAnswerFlag: true,
                      // 兜底：如果流结束但 answer 仍为空字符串，避免一直显示加载态
                      answer: prevAnswer === '' ? '暂无内容' : prevAnswer,
                    },
                  ],
                }
                break
              }
            }
            return newItems
          })
          return
        }

        // 正常的stream数据
        if (msg?.type === 'DATA' && msg?.content?.code === '00000000') {
          console.log('========================流式输出====================', msg)
          console.log('========================流式输出字符串====================', msg.content?.data)
          handleStreamMesageData(msg, question)
        }
        if (msg?.type === 'DATA' && msg?.content?.code === '01010005') {
          handleChatMaxCount(msg, question)
        }
      },
      abortControllerRef.current.signal,
    )
      .then(() => {
        // 流结束时执行（通过 Promise resolve 判断）
        // 如果是提质增效自动调用且本轮存在有效欢迎语候选，将其写入 sessionStorage 供欢迎语使用
        if (isAutoSubmitQualityImprovementRef.current && hasAutoWelcomeCandidateRef.current) {
          try {
            const key = 'toolStreamWelcomeText'
            sessionStorage.setItem(key, autoWelcomeCandidateRef.current)
          }
          catch (error) {
            console.error('[Chat] 写入提质增效欢迎语到 sessionStorage 失败:', error)
          }
        }
        // 清除自动调用标记
        isAutoSubmitQualityImprovementRef.current = false
        autoWelcomeCandidateRef.current = ''
        hasAutoWelcomeCandidateRef.current = false
        // 设置最后一条 AI 回答的 endAnswerFlag，用于控制打字效果结束
        setAllItems((prevItems) => {
          const newItems = [...prevItems]
          // 从后往前找到最后一个 AI 项
          for (let i = newItems.length - 1; i >= 0; i--) {
            if (newItems[i].role === 'ai' && newItems[i].answerList?.[0]) {
              const prevAnswer = newItems[i].answerList[0].answer
              newItems[i] = {
                ...newItems[i],
                answerList: [
                  {
                    ...newItems[i].answerList[0],
                    endAnswerFlag: true,
                    answer: prevAnswer === '' ? '暂无内容' : prevAnswer,
                  },
                ],
              }
              break
            }
          }
          return newItems
        })
        dispatch(setIsAsking(false))
        if (isNew) {
          setTimeout(() => {
            dispatch(fetchConversations())
          }, 2000)
        }
        // 业务洞察工作流处理：检查 AI 返回的 answer 是否需要开启子工作流
        const currentItems = allItems
        let lastAiItem = null
        for (let i = currentItems.length - 1; i >= 0; i--) {
          if (currentItems[i].role === 'ai' && currentItems[i].answerList?.[0]) {
            lastAiItem = currentItems[i]
            break
          }
        }
        if (lastAiItem) {
          const lastAnswer = lastAiItem.answerList?.[0]
          const wf = businessInsightWorkflowRef.current
          const shouldHandleWorkflowAnswer = Boolean(lastAnswer?.workFlowSessionId)
            || Boolean(wf?.mainWorkflowSessionId)
            || Boolean(wf?.isInSubWorkflow)
          if (lastAnswer && shouldHandleWorkflowAnswer) {
            const resolveWorkflowToolId = () => {
              try {
                return (sessionStorage.getItem('currentToolId') ?? '').trim()
                  || (currentToolId != null ? String(currentToolId).trim() : '')
              }
              catch {
                return currentToolId != null ? String(currentToolId).trim() : ''
              }
            }

            // 刚结束的流是「开子工作流」空问题请求：写入子 session，无卡片则自动「问子」
            if (expectingSubWorkflowOpenRef.current && lastAnswer.workFlowSessionId) {
              expectingSubWorkflowOpenRef.current = false
              const subRt = (
                pendingSubOpenRecordTypeRef.current?.trim()
                || (lastAnswer.recordType != null ? String(lastAnswer.recordType).trim() : '')
                || ''
              ).trim()
              pendingSubOpenRecordTypeRef.current = null
              if (subRt) {
                dispatch(setBusinessInsightSubWorkflow({
                  sessionId: String(lastAnswer.workFlowSessionId),
                  recordType: subRt,
                }))
                const hasCards = Array.isArray(lastAnswer.cardList) && lastAnswer.cardList.length > 0
                const pq = pendingSubQuestionRef.current
                pendingSubQuestionRef.current = null
                if (!hasCards && pq && pq.trim()) {
                  queueMicrotask(() => {
                    void handleSubmitQuestion(pq, undefined, resolveWorkflowToolId() || undefined, { busiType: '01' })
                  })
                }
              }
            }
            else if (expectingSubWorkflowOpenRef.current) {
              // 开子未带回 session，避免状态卡死
              expectingSubWorkflowOpenRef.current = false
              pendingSubOpenRecordTypeRef.current = null
              pendingSubQuestionRef.current = null
            }
            else {
              let parsedAnswer: { recordType?: unknown, question?: unknown, end?: unknown } | null = null
              try {
                parsedAnswer = JSON.parse(lastAnswer.answer || '')
              }
              catch {
                // 不是 JSON，保持正常回答
              }
              // 主工作流返回进子 JSON：先空问题开子（带主 session），再在流结束后写入子 session
              if (parsedAnswer && parsedAnswer.recordType && parsedAnswer.question != null) {
                const subRecordType = String(parsedAnswer.recordType).trim()
                const pendingQ = String(parsedAnswer.question)
                if (subRecordType) {
                  dispatch(setBusinessInsightPendingQuestion(pendingQ))
                  pendingSubQuestionRef.current = pendingQ
                  pendingSubOpenRecordTypeRef.current = subRecordType
                  expectingSubWorkflowOpenRef.current = true
                  queueMicrotask(() => {
                    void handleSubmitQuestion('', undefined, resolveWorkflowToolId() || undefined, {
                      recordType: subRecordType,
                      busiType: '01',
                    })
                  })
                }
              }
              else if (businessInsightWorkflowRef.current.isInSubWorkflow) {
                if (parsedAnswer && parsedAnswer.end === true) {
                  const reopenRt = parsedAnswer.recordType != null ? String(parsedAnswer.recordType).trim() : ''
                  const followQ = parsedAnswer.question != null ? String(parsedAnswer.question).trim() : ''
                  dispatch(exitBusinessInsightSubWorkflow())
                  dispatch(setBusinessInsightPendingQuestion(null))
                  queueMicrotask(() => {
                    void handleSubmitQuestion('', undefined, resolveWorkflowToolId() || undefined, {
                      busiType: '01',
                      ...(reopenRt ? { recordType: reopenRt } : {}),
                    })
                    if (followQ) {
                      window.setTimeout(() => {
                        void handleSubmitQuestion(followQ, undefined, resolveWorkflowToolId() || undefined, { busiType: '01' })
                      }, 400)
                    }
                  })
                }
              }
              else if (lastAnswer.workFlowSessionId && !businessInsightWorkflowRef.current.mainWorkflowSessionId) {
                dispatch(setBusinessInsightMainWorkflow(lastAnswer.workFlowSessionId))
              }
            }
          }
        }
      })
      .catch(() => {
        // 流式请求出错时的处理
        console.error('[Chat] 流式请求失败:')
        // 清除自动调用标记
        isAutoSubmitQualityImprovementRef.current = false
        // 设置最后一条 AI 回答的 endAnswerFlag，用于停止打字效果
        setAllItems((prevItems) => {
          const newItems = [...prevItems]
          // 从后往前找到最后一个 AI 项
          for (let i = newItems.length - 1; i >= 0; i--) {
            if (newItems[i].role === 'ai' && newItems[i].answerList?.[0]) {
              const prevAnswer = newItems[i].answerList[0].answer
              newItems[i] = {
                ...newItems[i],
                answerList: [
                  {
                    ...newItems[i].answerList[0],
                    endAnswerFlag: true,
                    answer: prevAnswer === '' ? '暂无内容' : prevAnswer,
                  },
                ],
              }
              break
            }
          }
          return newItems
        })
        dispatch(setIsAsking(false))
      })
  }

  /** 处理 workflow 表单提交 */
  const handleWorkflowSubmit = useCallback(async (paramMap: Record<string, string>, recordId?: string, workFlowSessionId?: string) => {
    const recordType = businessInsightWorkflowRef.current.subWorkflowRecordType?.trim() || 'A01'
    await handleSubmitQuestion('', undefined, undefined, {
      paramMap,
      recordId,
      workFlowSessionId,
      recordType,
      busiType: '01',
    })
  }, [])

  /** 获取qa记录 */
  const getUserQaRecordPage = useCallback(async (conversationId: string, toolId?: string) => {
    // 检查是否正在处理相同的 conversationId，避免重复调用
    if (processingConversationIdRef.current === conversationId) {
      return
    }
    setIsLoading(true)
    // 标记正在处理
    processingConversationIdRef.current = conversationId
    // 定义 finalConversationId 在 try 块外，以便 finally 块可以访问
    let finalConversationId = conversationId
    try {
      // 检测是否从收藏页返回（优先使用 ref 中保存的值，避免 location.state 被清除后丢失）
      // 增加 sessionStorage 检查，用于 navigate(-1) 的情况
      const fromCollect = fromCollectRef.current || Boolean(location.state?.fromCollect) || Boolean(sessionStorage.getItem('fromCollect'))
      // 如果从收藏页返回，先调用 get_user_conversation_session 获取新的会话ID
      if (fromCollect && !fromCollectProcessedRef.current) {
        fromCollectProcessedRef.current = true
        const sessionToolId = safeSessionStorageGetItem('currentToolId') || ''
        try {
          await waitForToken()
          const sessionRes = await fetchSessionConversationId({ busiId: sessionToolId })
          if (sessionRes?.data?.conversationId) {
            finalConversationId = sessionRes.data.conversationId
            // 如果获取到新会话ID，设置标记避免路由变化时重复调用
            toolHistoryLoadedRef.current.conversationId = finalConversationId
            // 更新 processingConversationIdRef 为新会话ID，避免使用旧ID重复调用
            processingConversationIdRef.current = finalConversationId
          }
        }
        catch (error) {
          console.error('[Chat] 从收藏返回 - 获取会话ID失败:', error)
          // 如果获取失败，继续使用原来的 conversationId
        }
      }

      // 如果从收藏页返回，触发事件通知 HomeNew 刷新问题列表
      if (fromCollect) {
        const eventToolId = toolId || currentToolId || safeSessionStorageGetItem('currentToolId') || ''
        // 清除 sessionStorage 中的标记，避免影响后续路由
        sessionStorage.removeItem('fromCollect')
        // 延迟触发事件，确保 Home 组件的监听器已注册
        setTimeout(() => {
          window.dispatchEvent(new CustomEvent('refreshQuestionsFromCollect', {
            detail: {
              toolId: eventToolId,
            },
          }))
        }, 100)
      }
      await waitForToken()
      const res = await fetchUserQaRecordPage(finalConversationId, toolId || safeSessionStorageGetItem('currentToolId') || '')
      const qaRecords = res.data || []
      const wfCtx = getLastQaRecordWorkflowContext(qaRecords)
      lastLoadedQaWorkflowContextRef.current = wfCtx.recordType && wfCtx.workFlowSessionId
        ? {
            recordType: wfCtx.recordType,
            workFlowSessionId: wfCtx.workFlowSessionId,
            busiType: wfCtx.busiType ?? '01',
          }
        : null
      const messages = [{ role: 'system' } as ChatRecord, ...processApiResponse(qaRecords)]
      // 处理历史记录中的参考文档标记
      const processedMessages = messages.map((item) => {
        if (item.role === 'ai' && item.answerList?.[0]?.answer) {
          return {
            ...item,
            answerList: item.answerList.map(answerItem => ({
              ...answerItem,
              answer: answerItem.answer
                // 移除括号内容，但保留 Markdown 链接语法中的 ](...)
                ?.replace(/\([^)]*\)/g, (match, offset, str) => (str[offset - 1] === ']' ? match : ''))
                .replace(/\[参考文档(?:《[^》]*》\s*)+\]/g, '')
                .trim(),
            })),
          }
        }
        return item
      })
      setAllItems(processedMessages)
      // 优先从 qaRecords 中查找 toolId（这是实际使用的）
      const latestToolId = [...qaRecords].reverse().find(item => Boolean(item.toolId))?.toolId?.trim?.()
      const hasQaRecords = qaRecords.length > 0
      // 如果 qaRecords 中没有 toolId，尝试从 conversations 中查找当前会话的 toolId（会话级别）
      const conversationToolId = latestToolId || (conversations.find(conv => conv.conversationId === finalConversationId)?.toolId?.trim?.())
        // 优先使用从 location.state 传递的 toolId（如果存在），这是从历史记录点击传递过来的
      const toolIdFromState = toolIdFromStateRef.current !== undefined
        ? (toolIdFromStateRef.current ? String(toolIdFromStateRef.current) : null)
        : undefined

      // 确定最终使用的 toolId：优先使用从 location.state 传递的，其次使用 qaRecords 中的，最后使用 conversation 中的
      // 如果从 location.state 传递了 toolId，直接使用它（最高优先级）
      if (toolIdFromState !== undefined) {
        if (toolIdFromState) {
          // 只有当 Redux 中的 toolId 与最终确定的 toolId 不一致时，才更新
          if (currentToolId !== toolIdFromState) {
            dispatch(setCurrentToolId(toolIdFromState))
          }
          // 无条件同步到 sessionStorage，确保 ChatEditor 和 handleSubmitQuestion 能获取到正确的 toolId
          sessionStorage.setItem('currentToolId', toolIdFromState)
        }
        else {
          // 如果从 location.state 传递的是 null，清除 toolId
          if (currentToolId) {
            dispatch(clearCurrentToolId())
          }
          // 清除 sessionStorage，确保制度活化模式正确
          sessionStorage.removeItem('currentToolId')
        }
        // 清除 ref，避免下次路由变化时误用
        toolIdFromStateRef.current = undefined
      }
      else {
        // 如果没有从 location.state 传递 toolId（可能是嵌套路由传递失败），使用原来的逻辑
        // 优先使用 qaRecords 中的 toolId，其次使用 conversation 中的 toolId
        const finalToolId = latestToolId || conversationToolId || undefined

        if (finalToolId) {
          // 只有当 Redux 中的 toolId 与最终确定的 toolId 不一致时，才更新
          if (currentToolId !== finalToolId) {
            dispatch(setCurrentToolId(finalToolId))
            // 从收藏返回时，同步到 sessionStorage，避免 ChatEditor 清除 toolId
            if (fromCollect) {
              sessionStorage.setItem('currentToolId', finalToolId)
            }
          }
          else {
            // 从收藏返回时，确保 sessionStorage 中有值
            if (fromCollect && !sessionStorage.getItem('currentToolId')) {
              sessionStorage.setItem('currentToolId', finalToolId)
            }
          }
        }
        else {
          // 如果 qaRecords 和 conversation 中都没有 toolId
          // 如果有历史记录但没有 toolId，说明是制度活化，应该清除
          if (hasQaRecords && currentToolId) {
            dispatch(clearCurrentToolId())
          }
          // 如果没有历史记录，可能是新会话，但如果 Redux 中已经有 toolId（从 HistoryBarList 设置的），暂时保留
          // 因为可能是刚点击历史记录但 API 还没返回，或者 location.state 传递失败但 Redux 中已有正确的值
          else if (!hasQaRecords && currentToolId) {
            if (fromCollect && !sessionStorage.getItem('currentToolId')) {
              sessionStorage.setItem('currentToolId', currentToolId)
            }
          }
        }
      }
    }
    catch {
      lastLoadedQaWorkflowContextRef.current = null
    }
    finally {
      setIsLoading(false)
      // 标记该会话的历史记录已加载完成
      historyLoadedRef.current.conversationId = finalConversationId
      // finalConversationId 可能是新会话ID（从收藏返回时）或原来的 conversationId
      if (processingConversationIdRef.current === finalConversationId) {
        processingConversationIdRef.current = null
      }
      // 如果历史记录加载完成且有待发送的问题，触发自动发送
      if (pendingQuestionRef.current && finalConversationId === currentIdRef.current) {
        const questionToSend = pendingQuestionRef.current
        // 检查是否已经发送过相同的问题
        if (questionToSend !== lastSentQuestionRef.current) {
          lastSentQuestionRef.current = questionToSend
          pendingQuestionRef.current = null
          // 清除 shouldSendQuestion（如果还存在）
          dispatch(clearShouldSendQuestion())
          // 延迟发送，确保状态已更新
          setTimeout(() => {
            // 左侧常见问题自动发送：若 QA 列表最后一条带 recordType + workFlowSessionId，一并透传
            const wfExtra = lastLoadedQaWorkflowContextRef.current
            const autoExtra = wfExtra?.recordType && wfExtra?.workFlowSessionId
              ? { recordType: wfExtra.recordType, workFlowSessionId: wfExtra.workFlowSessionId, busiType: wfExtra.busiType ?? '01' }
              : undefined
            handleSubmitQuestion(questionToSend, undefined, currentToolId, autoExtra)
          }, 100)
        }
      }
    }
  }, [dispatch, currentToolId, conversations, location.state])

  /** 点击滚动到底部 */
  const scrollToBottom = () => {
    scrollableRef.current.scrollTo(scrollableRef.current.scrollHeight, { behavior: 'smooth' })
  }

  useEffect(() => {
    if (id) {
      // 检查是否已通过 toolHistoryLoaded 事件加载过相同会话的数据
      // 如果已加载，跳过接口调用，避免重复请求
      if (toolHistoryLoadedRef.current.conversationId === id) {
        // 已加载，清除标记，避免影响后续正常的路由切换
        toolHistoryLoadedRef.current.conversationId = null
        // 更新 currentIdRef，确保状态一致
        currentIdRef.current = id
        return
      }

      // 检查是否正在通过工具切换加载历史记录（ChatEditor 正在处理）
      // 通过 sessionStorage 标记判断，避免时序问题导致的重复调用
      const toolHistoryLoadingId = sessionStorage.getItem('toolHistoryLoading')
      if (toolHistoryLoadingId === id) {
        currentIdRef.current = id
        // 更新 toolId 相关状态（如果有）
        if (initialToolId !== undefined) {
          toolIdFromStateRef.current = initialToolId
        }
        return
      }

      // 检查是否跳过历史记录加载（点击常见问题时）
      const skipHistoryLoad = Boolean((location.state as { skipHistoryLoad?: boolean } | null)?.skipHistoryLoad)
      if (skipHistoryLoad) {
        lastLoadedQaWorkflowContextRef.current = null
        setAllItems(prev => (prev.length > 0 ? prev : ([{ role: 'system' } as ChatRecord])))
        currentIdRef.current = id
        // 更新 toolId 相关状态（如果有）
        if (initialToolId !== undefined) {
          toolIdFromStateRef.current = initialToolId
        }
        return
      }

      // 如果 id 没有变化，只是 location.state 变化，需要判断是否需要重新加载历史记录
      if (currentIdRef.current === id) {
        // 检查是否从收藏页返回（需要重新加载历史记录）
        const fromCollect = Boolean(location.state?.fromCollect) || Boolean(sessionStorage.getItem('fromCollect'))
        // 如果 allItems 为空，说明是首次加载，需要加载历史记录
        if (!fromCollect && allItems.length > 0) {
          return
        }
      }

      // 停止之前的请求
      if (abortControllerRef.current) {
        abortControllerRef.current.abort()
        dispatch(setIsAsking(false))
      }
      currentIdRef.current = id
      lastSentQuestionRef.current = '' // 重置标记
      pendingQuestionRef.current = null // 清除待发送的问题
      // 重置历史记录加载标记，确保新会话时能正确触发自动发送
      historyLoadedRef.current.conversationId = null
      lastLoadedQaWorkflowContextRef.current = null
      // 保存 fromCollect 标记到 ref，避免 location.state 被清除后丢失
      // 优先使用 location.state，其次使用 sessionStorage（用于 navigate(-1) 的情况）
      fromCollectRef.current = Boolean(location.state?.fromCollect) || Boolean(sessionStorage.getItem('fromCollect'))
      // 重置 fromCollect 处理标记，确保每次路由变化时都能正确处理
      fromCollectProcessedRef.current = false
      // 清除处理标记，允许新的 conversationId 处理
      processingConversationIdRef.current = null

      // 等待 token 就绪后再调用接口
      waitForToken().then(() => {
        getUserQaRecordPage(id)
      })
    }
  }, [id, location.state])

  // 处理shouldSendQuestion的变化 - 自动发送问题
  useEffect(() => {
    if (
      shouldSendQuestion
      && currentIdRef.current
      && !isLoading
      && shouldSendQuestion !== lastSentQuestionRef.current
    ) {
      // 如果当前会话已有历史记录（allItems.length > 1），需要等待历史记录加载完成
      // 如果历史记录已加载完成（historyLoadedRef.current.conversationId === currentIdRef.current），可以立即发送
      // 如果是新会话（allItems.length <= 1），可以立即发送
      const canSend = historyLoadedRef.current.conversationId === currentIdRef.current || allItems.length <= 1
      if (canSend) {
        const questionToSend = shouldSendQuestion
        console.log('[Chat] auto send triggered (shouldSendQuestion):', {
          conversationId: currentIdRef.current,
          question: questionToSend,
          currentToolId,
        })
        lastSentQuestionRef.current = questionToSend
        pendingQuestionRef.current = null
        // 立即清除shouldSendQuestion，防止重复发送
        dispatch(clearShouldSendQuestion())
        // 确保历史记录加载完成后再发送问题
        setTimeout(() => {
          console.log('[Chat] 执行自动发送问题:', questionToSend)
          const wfExtra = lastLoadedQaWorkflowContextRef.current
          const autoExtra = wfExtra?.recordType && wfExtra?.workFlowSessionId
            ? { recordType: wfExtra.recordType, workFlowSessionId: wfExtra.workFlowSessionId, busiType: wfExtra.busiType ?? '01' }
            : undefined
          handleSubmitQuestion(questionToSend, undefined, currentToolId, autoExtra)
        }, 100)
      }
      else {
        // 如果历史记录还在加载中，保存待发送的问题，等待历史记录加载完成后再发送
        pendingQuestionRef.current = shouldSendQuestion
      }
    }
  }, [shouldSendQuestion, isLoading, allItems.length, currentToolId, id])

  // 根据 currentToolId 获取对应的 toolName
  useEffect(() => {
    const getToolNameFromToolId = async () => {
      if (currentToolId) {
        try {
          const cachedRow = findToolRowBySessionToolId(readToolListFromSessionStorage(), currentToolId)
          if (cachedRow?.toolName?.trim()) {
            setCurrentToolName(cachedRow.toolName.trim())
            return
          }
          // 兼容旧缓存键
          const userRoles = getUserRolesForApi()
          const legacyKey = `toolList_${JSON.stringify(userRoles)}`
          const cached = sessionStorage.getItem(legacyKey)

          if (cached) {
            try {
              const { toolList, timestamp } = JSON.parse(cached)
              if (Date.now() - timestamp < 5 * 60 * 1000) {
                const tool = toolList.find((t: any) => String(t.toolId) === String(currentToolId))
                if (tool?.toolName) {
                  setCurrentToolName(String(tool.toolName).trim())
                }
              }
            }
            catch {
              // 缓存解析失败，继续调用接口
            }
          }
        }
        catch (error) {
          console.error('获取工具名称失败:', error)
        }
      }
      else {
        const list = readToolListFromSessionStorage()
        const general = findGeneralToolRow(list)
        setCurrentToolName(general?.toolName?.trim() || undefined)
      }
    }
    getToolNameFromToolId()
  }, [currentToolId])

  // 监听工具按钮点击事件，更新 ChatWelcome 提示语和 toolId
  useEffect(() => {
    const handleToolClickEvent = (event: CustomEvent) => {
      const { isToolBtn, toolId, toolName } = event.detail
      // 保存当前选择的 toolName
      setCurrentToolName(toolName)
      // 保存当前选择的 toolId 到 Redux
      if (!isToolBtn && toolId) {
        // 提质增效模式，保存 toolId
        dispatch(setCurrentToolId(toolId))
      }
      else {
        // 制度活化，清除 toolId
        dispatch(clearCurrentToolId())
      }
      // 历史记录加载已由 ChatEditor 通过 toolHistoryLoaded 事件处理，此处不再重复调用
    }
    window.addEventListener('toolButtonClick', handleToolClickEvent as EventListener)
    return () => {
      window.removeEventListener('toolButtonClick', handleToolClickEvent as EventListener)
    }
  }, [dispatch])

  // 监听工具历史记录加载事件，渲染历史会话
  useEffect(() => {
    const handleToolHistoryLoaded = (event: CustomEvent) => {
      const { conversationId, toolId, toolName, qaRecords } = event.detail
      setIsLoading(true)
      try {
        const qaList = Array.isArray(qaRecords) ? qaRecords : []
        const wfEvt = getLastQaRecordWorkflowContext(qaList)
        lastLoadedQaWorkflowContextRef.current = wfEvt.recordType && wfEvt.workFlowSessionId
          ? {
              recordType: wfEvt.recordType,
              workFlowSessionId: wfEvt.workFlowSessionId,
              busiType: wfEvt.busiType ?? '01',
            }
          : null
        // 标记已通过事件加载数据，避免 useEffect 重复调用接口
        toolHistoryLoadedRef.current.conversationId = conversationId
        // 更新当前会话ID
        currentIdRef.current = conversationId
        // 处理历史记录数据
        const messages = [{ role: 'system' } as ChatRecord, ...processApiResponse(qaList)]
        // 处理历史记录中的参考文档标记
        const processedMessages = messages.map((item) => {
          if (item.role === 'ai' && item.answerList?.[0]?.answer) {
            return {
              ...item,
              answerList: item.answerList.map(answerItem => ({
                ...answerItem,
                answer: answerItem.answer
                  // 移除括号内容，但保留 Markdown 链接语法中的 ](...)
                  ?.replace(/\([^)]*\)/g, (match, offset, str) => (str[offset - 1] === ']' ? match : ''))
                  .replace(/\[参考文档(?:《[^》]*》\s*)+\]/g, '')
                  .trim(),
              })),
            }
          }
          return item
        })
        setAllItems(processedMessages)
        // 更新 toolName
        if (toolName) {
          setCurrentToolName(toolName)
        }
        // 更新 toolId
        if (toolId) {
          dispatch(setCurrentToolId(toolId))
        }
      }
      catch (error) {
        console.error('处理历史记录失败:', error)
        lastLoadedQaWorkflowContextRef.current = null
      }
      finally {
        setIsLoading(false)
        // 标记该会话的历史记录已加载完成（通过工具切换事件加载）
        historyLoadedRef.current.conversationId = conversationId
        // 清除 toolHistoryLoading 标记，避免影响后续路由切换
        const toolHistoryLoadingId = sessionStorage.getItem('toolHistoryLoading')
        if (toolHistoryLoadingId === conversationId) {
          sessionStorage.removeItem('toolHistoryLoading')
        }
      }
    }
    window.addEventListener('toolHistoryLoaded', handleToolHistoryLoaded as EventListener)
    return () => {
      window.removeEventListener('toolHistoryLoaded', handleToolHistoryLoaded as EventListener)
    }
  }, [dispatch])

  // 监听自动提问事件（提质增效模式下使用）
  useEffect(() => {
    const handleAutoSubmitQuestion = (event: CustomEvent) => {
      const { conversationId, question, toolId, recordType, busiType } = event.detail
      // 确保当前会话ID匹配
      if (conversationId === currentIdRef.current) {
        const wf = lastLoadedQaWorkflowContextRef.current
        if (wf?.recordType && wf?.workFlowSessionId) {
          handleSubmitQuestion(question, undefined, toolId, {
            recordType: wf.recordType,
            workFlowSessionId: wf.workFlowSessionId,
            busiType: wf.busiType ?? busiType ?? '01',
          })
        }
        else {
          handleSubmitQuestion(question, undefined, toolId, { recordType, busiType })
        }
      }
      else {
        console.warn('[Chat] conversationId 不匹配，跳过自动提交', {
          eventConversationId: conversationId,
          currentIdRef: currentIdRef.current,
        })
      }
    }
    window.addEventListener('autoSubmitQuestion', handleAutoSubmitQuestion as EventListener)
    return () => {
      window.removeEventListener('autoSubmitQuestion', handleAutoSubmitQuestion as EventListener)
    }
  }, [handleSubmitQuestion])

  return (
    <div className={styles.scrollView}>
      <div className={`${styles.chatPage} relative`}>
        <div className={`${styles.content}`}>
          {isLoading && (
            <div className="w-full h-full flex justify-center items-center">
              <SdreamLoading />
            </div>
          )}
          {!isLoading && (
            <motion.div
              ref={scrollableRef}
              initial={{ opacity: 0, y: -10 }}
              animate={{ opacity: 1, y: 0 }}
              transition={{
                duration: 0.3,
                opacity: { duration: 0.1 },
              }}
              className={`${styles.scrollable} scrollbar-hide scroll-smooth`}
            >
              <div className={styles.inter}>
                {allItems.map((record, index) => {
                  const recordId = record.answerList?.[0]?.recordId || record.groupId
                  const uniqueKey = recordId
                    ? `${record.role}-${recordId}`
                    : `${record.role}-${index}`

                  // 如果历史记录中 firstQaFlag 为 true，隐藏 UI 但保留组件渲染（确保自动提交逻辑能执行）
                  const shouldHideHistoryItem = record.role === 'ai' && record.answerList?.[0]?.firstQaFlag === true
                  // 如果是自动调用提问接口（空问题且是流式返回的新记录），不显示问题和回答
                  // 判断条件：question === undefined（空问题）且 isShow === false（流式返回的新记录，不是历史记录）
                  const shouldHideEmptyQuestionAnswer = record.role === 'ai' && record.question === undefined && record.answerList?.[0]?.isShow === false
                  // 白名单：当同一条 AI 记录里同时有 question + answer（且 firstQaFlag 不为 true）时，强制展示，避免误隐藏
                  const hasQuestion = typeof record.question === 'string' && record.question.trim().length > 0
                  const firstAnswer = record.answerList?.[0]
                  const hasAnswer = typeof firstAnswer?.answer === 'string' && firstAnswer.answer.trim().length > 0
                  const hasCardList = Array.isArray(firstAnswer?.cardList) && firstAnswer!.cardList.length > 0
                  const shouldForceShow = record.role === 'ai'
                    && hasQuestion
                    && (hasAnswer || hasCardList)
                    && firstAnswer?.firstQaFlag !== true
                  return (
                  <div
                    className="w-full chatItem mx-auto"
                    key={uniqueKey}
                    style={(!shouldForceShow && (shouldHideHistoryItem || shouldHideEmptyQuestionAnswer)) ? { visibility: 'hidden', height: 0, overflow: 'hidden', margin: 0, padding: 0 } : undefined}
                  >
                    {record.role === 'system' && <ChatWelcome toolName={currentToolName} welcomeText={(record as any).welcomeText} />}
                    {record.role === 'user' && <ChatItemUser record={record} />}
                    {record.role === 'ai' && (
                      <ChatAnswerBox
                        onSubmitQuestion={handleSubmitQuestion}
                        isLastAnswer={index === allItems.length - 1}
                        showIndex={0}
                        record={record}
                        index={index}
                        onWorkflowSubmit={handleWorkflowSubmit}
                        isWorkflowSubmitting={isAsking}
                        allItems={allItems}
                      />
                    )}
                  </div>
                  )
                })}
              </div>
            </motion.div>
          )}
        </div>
        <div className="relative box-border px-[0] mx-auto iptContainer w-full flex-shrink-0 sm:px-0 pb-[18px]">
          <div className="absolute left-1/2 ml-[-20px] top-[-45px] sm:top-[-65px]">
            <motion.div
              initial="hidden"
              animate={(position?.top as number) < -20 ? 'visible' : 'hidden'}
              variants={{
                hidden: { opacity: 0, y: 20, pointerEvents: 'none' as const },
                visible: { opacity: 1, y: 0, pointerEvents: 'auto' as const },
              }}
              transition={{ duration: 0.3, ease: 'easeInOut' }}
            >
              <Button onPress={scrollToBottom} radius="full" isIconOnly color="primary">
                <ScrollBtoIcon />
              </Button>
            </motion.div>
          </div>
          <ChatEditor
            onSubmit={(question, toolId) => handleSubmitQuestion(question, undefined, toolId)}
            onToolClick={(isToolBtn, toolId, toolName, shouldChangeStyle, conversationId, isLoading, toolMeta) => {
            // 如果传递了 loading 状态，更新 isLoading
            if (isLoading !== undefined) {
              setIsLoading(isLoading)
            }
            // 只在真正的工具切换时触发事件（有 conversationId 时），避免 loading 状态更新时重复触发
            if (conversationId) {
              window.dispatchEvent(new CustomEvent('toolButtonClick', {
                detail: { isToolBtn, toolId, toolName, shouldChangeStyle, conversationId, source: 'toolButton', toolMeta },
              }))
            }
          }}
            placeholders={[]}
          />
          <div className="hidden sm:block w-full text-center mt-[12px] text-[#3333334d] text-[12px]">
            内容由AI模型生成，其准确性和完整性无法保证，仅供参考
          </div>
        </div>
      </div>
    </div>
  )
}
