import { reactive, computed, nextTick } from 'vue'
import { ServeTalkRecords } from '@/api/chat'
import { useDialogueStore } from '@/store'
import { ITalkRecord } from '@/types/chat'
import { formatTalkRecord } from '@/utils/talk'
import { addClass, removeClass, scrollToBottom, isScrollAtBottom } from '@/utils/dom'

interface Params {
  receiver_id: number
  talk_type: number
  limit: number
}

interface SpecialParams extends Params {
  msg_id?: string
  cursor?: number
  direction?: 'up' | 'down'
  sort_sequence?: string
  type?: 'loadMore'
}

interface LoadOptions {
  specifiedMsg?: SpecialParams
  middleMsgCreatedAt?: string
}

export const useTalkRecord = (uid: number) => {
  const dialogueStore = useDialogueStore()

  const records = computed((): ITalkRecord[] => dialogueStore.records)

  const location = reactive({
    msgid: '',
    num: 0
  })

  const loadConfig = reactive({
    receiver_id: 0,
    talk_type: 0,
    status: 0,
    cursor: 0,
    specialParams: undefined as SpecialParams | undefined,
    isLocatingMessage: false,
    isLoadingMore: false,
    lastLoadMoreTime: 0,
    targetMessagePosition: 0
  })

  // 重置 loadConfig
  const resetLoadConfig = () => {
    loadConfig.receiver_id = 0
    loadConfig.talk_type = 0
    loadConfig.status = 0
    loadConfig.cursor = 0
    loadConfig.specialParams = undefined
  }

  const onJumpMessage = (msgid: string) => {
    const element = document.getElementById(msgid)
    if (!element) {
      if (location.msgid == '') {
        location.msgid = msgid
        location.num = 3
      } else {
        location.num--

        if (location.num === 0) {
          location.msgid = ''
          location.num = 0
          window['$message'].info('仅支持查看最近300条的记录')
          return
        }
      }

      const el = document.getElementById('imChatPanel')

      return el?.scrollTo({
        top: 0,
        behavior: 'smooth'
      })
    }

    location.msgid = ''
    location.num = 0

    // 使用更精确的滚动定位方式
    const el = document.getElementById('imChatPanel')
    if (el && element) {
      // 计算目标元素相对于容器的偏移量
      const targetOffsetTop = element.offsetTop
      const containerHeight = el.clientHeight
      const targetHeight = element.offsetHeight

      // 计算理想的滚动位置：让目标元素居中显示
      let scrollTo = targetOffsetTop - containerHeight / 2 + targetHeight / 2

      // 边界检查：确保目标元素完全在可视区域内
      const minScrollTop = 0
      const maxScrollTop = el.scrollHeight - containerHeight

      // 如果计算出的位置超出边界，调整到边界内
      if (scrollTo < minScrollTop) {
        scrollTo = minScrollTop
      } else if (scrollTo > maxScrollTop) {
        scrollTo = maxScrollTop
      }

      // 执行滚动
      el.scrollTo({ top: scrollTo, behavior: 'smooth' })
    } else {
      // 降级方案：使用 scrollIntoView
      element?.scrollIntoView({
        behavior: 'smooth',
        block: 'center'
      })
    }

    addClass(element, 'border')

    setTimeout(() => {
      element && removeClass(element, 'border')
    }, 3000)
  }

  // 加载数据列表
  const load = async (params: Params) => {
    // 使用性能标记测量加载时间
    const startTime = performance.now()
    
    const request = {
      talk_type: params.talk_type,
      receiver_id: params.receiver_id,
      cursor: loadConfig.cursor,
      limit: 30
    }
    
    // 如果不是从本地数据库加载的，则设置加载状态为0（加载中）
    if (loadConfig.status !== 2 && loadConfig.status !== 3) {
      loadConfig.status = 0
    }

    // 记录当前滚动高度，用于后续保持滚动位置
    let scrollHeight = 0
    const el = document.getElementById('imChatPanel')
    if (el) {
      scrollHeight = el.scrollHeight
    }
    
    // 发起网络请求获取服务器数据
    const { data, code } = await ServeTalkRecords(request)
    
    // 处理请求失败的情况
    if (code != 200) {
      // 如果已经从本地加载了数据，保持原状态
      loadConfig.status = (loadConfig.status === 2 || loadConfig.status === 3) ? loadConfig.status : 1
      return
    }
    
    // 防止对话切换过快，数据渲染错误
    if (request.talk_type != loadConfig.talk_type || request.receiver_id != loadConfig.receiver_id) {
      location.msgid = ''
      return
    }

    // 优化：使用批量处理而不是map，减少内存分配
    const serverItems = data.items || []
    const items = new Array(serverItems.length)
    for (let i = 0; i < serverItems.length; i++) {
      items[i] = formatTalkRecord(uid, serverItems[i])
    }

    // 同步到本地数据库（异步操作，不阻塞UI更新）
    const syncToLocalDB = async () => {
      try {
        const syncStartTime = performance.now()
        const { batchAddOrUpdateMessages } = await import('@/utils/db')
        await batchAddOrUpdateMessages(serverItems, params.talk_type, params.receiver_id, true, 'sequence')
        const syncEndTime = performance.now()
        console.log(`聊天记录已同步到本地数据库，耗时: ${(syncEndTime - syncStartTime).toFixed(2)}ms`)
      } catch (error) {
        console.error('同步聊天记录到本地数据库失败:', error)
      }
    }
    
    // 启动异步同步过程
    syncToLocalDB()

    // 如果是从本地数据库加载的数据，且服务器返回的数据与本地数据相同，则不需要更新UI
    if ((loadConfig.status === 2 || loadConfig.status === 3) && request.cursor === 0) {
      try {
        const compareStartTime = performance.now()
        
        // 获取最新的本地数据库消息进行比较
        const { getMessages } = await import('@/utils/db')
        const localMessages = await getMessages(
          params.talk_type,
          uid,
          params.receiver_id,
          items.length || 30, // 获取与服务器返回数量相同的消息
          0, // 从第一页开始
          'sequence' // 明确指定排序字段
        )
        
        // 快速路径：如果本地消息数量与服务器不同，直接更新UI
        if (localMessages.length !== items.length) {
          console.log('本地数据与服务器数据数量不一致，更新UI')
        } else if (items.length > 0) {
          // 优化：使用位图标记需要更新的消息，减少内存使用
          const needsUpdate = new Uint8Array(items.length)
          let updateCount = 0
          
          // 优化：使用哈希表存储消息ID到索引的映射，加速查找
          const serverMsgMap = new Map()
          for (let i = 0; i < items.length; i++) {
            serverMsgMap.set(items[i].msg_id, i)
          }
          
          // 优化：首先检查首尾消息，如果它们匹配，再使用抽样检查中间消息
          const firstLocalMsg = localMessages[0]
          const lastLocalMsg = localMessages[localMessages.length - 1]
          
          const firstServerIdx = serverMsgMap.get(firstLocalMsg.msg_id)
          const lastServerIdx = serverMsgMap.get(lastLocalMsg.msg_id)
          
          // 如果首尾消息ID存在于服务器数据中，进行详细比较
          if (firstServerIdx !== undefined && lastServerIdx !== undefined) {
            // 根据用户建议，只比较msg_id和is_revoke字段
            // 因为消息ID是唯一的，内容变化主要是由撤回操作引起的
            const compareMessage = (localMsg, serverMsg) => {
              // 消息ID已在外部比较过，这里只需检查is_revoke状态
              return localMsg.is_revoke === serverMsg.is_revoke
            }
            
            const firstMatch = compareMessage(firstLocalMsg, items[firstServerIdx])
            const lastMatch = compareMessage(lastLocalMsg, items[lastServerIdx])
            
            // 如果首尾消息匹配，进行全量检查所有消息
            if (firstMatch && lastMatch) {
              // 全量检查策略：检查所有消息
              // 由于一次只有30条消息，全量检查不会带来太大的性能负担
              let allMatch = true
              
              // 遍历所有本地消息，与服务器消息进行比较
              for (let i = 0; i < localMessages.length; i++) {
                const localMsg = localMessages[i]
                const serverIdx = serverMsgMap.get(localMsg.msg_id)
                
                // 如果消息ID不存在于服务器数据中，或者消息内容不匹配
                if (serverIdx === undefined || !compareMessage(localMsg, items[serverIdx])) {
                  allMatch = false
                  console.log(`消息不匹配，索引: ${i}, 消息ID: ${localMsg.msg_id}`)
                  break // 一旦发现不匹配，立即退出循环
                }
              }
              
              if (allMatch) {
                const compareEndTime = performance.now()
                console.log(`本地数据与服务器数据一致（全量检查），无需更新UI，比较耗时: ${(compareEndTime - compareStartTime).toFixed(2)}ms`)
                return
              }
            }
          }
          
          console.log('本地数据与服务器数据不一致，更新UI')
        }
      } catch (error) {
        console.error('比较本地数据和服务器数据时出错:', error)
        // 出错时默认更新UI
      }
    }

    // 更新UI
    const updateUIStartTime = performance.now()
    
    if (request.cursor == 0) {
      // 判断是否是初次加载
      dialogueStore.clearDialogueRecord()
    }

    // 反转消息顺序并添加到对话记录
    dialogueStore.unshiftDialogueRecord(items.reverse())
    
    // 更新加载状态
    loadConfig.status = items.length >= request.limit ? 1 : 2
    loadConfig.cursor = data.cursor

    // 使用requestAnimationFrame代替nextTick，提高滚动性能
    requestAnimationFrame(() => {
      const el = document.getElementById('imChatPanel')
      if (el) {
        if (request.cursor == 0) {
          console.log('滚动到底部')
          
          // 在初次加载完成后恢复上传任务
          dialogueStore.restoreUploadTasks()
          
          // 使用优化的滚动函数
          scrollToBottom()
        } else {
          // 保持滚动位置
          el.scrollTop = el.scrollHeight - scrollHeight
        }
      }

      // 如果有需要定位的消息ID，执行定位
      if (location.msgid) {
        onJumpMessage(location.msgid)
      }
      
      const updateUIEndTime = performance.now()
      const totalEndTime = performance.now()
      
      console.log(`UI更新耗时: ${(updateUIEndTime - updateUIStartTime).toFixed(2)}ms`)
      console.log(`load函数总耗时: ${(totalEndTime - startTime).toFixed(2)}ms`)
    })
  }

  // 获取当前消息的最小 sequence
  const getMinSequence = () => {
    if (!records.value.length) return 0
    return Math.min(...records.value.map((item) => item.sequence))
  }
  // 获取当前消息的最大 sequence
  const getMaxSequence = () => {
    if (!records.value.length) return 0
    return Math.max(...records.value.map((item) => item.sequence))
  }

  // 本地数据库加载缓存，用于优化短时间内的重复加载
  const localDBCache = {
    key: '', // 缓存键：talk_type-receiver_id
    data: null, // 缓存的消息数据
    timestamp: 0, // 缓存时间戳
    ttl: 2000 // 缓存有效期（毫秒）
  }
  
  // 从本地数据库加载聊天记录
  const loadFromLocalDB = async (params: Params) => {
    try {
      // 使用性能标记测量加载时间
      const startTime = performance.now()
      
      // 生成缓存键
      const cacheKey = `${params.talk_type}-${params.receiver_id}`
      
      // 检查缓存是否有效
      const now = Date.now()
      if (localDBCache.key === cacheKey && 
          localDBCache.data && 
          now - localDBCache.timestamp < localDBCache.ttl) {
        console.log('使用缓存的本地数据库消息')
        
        // 清空现有记录
        dialogueStore.clearDialogueRecord()
        
        // 直接使用缓存数据
        dialogueStore.unshiftDialogueRecord([...localDBCache.data]) // 创建副本避免引用问题
        
        // 设置加载状态为完成（3表示从本地数据库加载完成）
        loadConfig.status = 3
        
        // 恢复上传任务
        dialogueStore.restoreUploadTasks()
        
        // 使用requestAnimationFrame优化滚动性能
        requestAnimationFrame(() => {
          scrollToBottom()
        })
        
        const endTime = performance.now()
        console.log(`从缓存加载聊天记录耗时: ${(endTime - startTime).toFixed(2)}ms，加载了${localDBCache.data.length}条记录`)
        
        return true
      }
      
      // 导入 getMessages 函数
      const { getMessages } = await import('@/utils/db')
      
      // 从本地数据库获取聊天记录，使用sequence作为排序字段以提高性能
      const localMessages = await getMessages(
        params.talk_type,
        uid,
        params.receiver_id,
        params.limit || 30,
        0, // 从第一页开始
        'sequence' // 明确指定排序字段
      )
      
      // 如果有本地数据
      if (localMessages && localMessages.length > 0) {
        // 清空现有记录
        dialogueStore.clearDialogueRecord()
        
        // 优化：预分配数组大小，减少内存重分配
        const formattedMessages = new Array(localMessages.length)
        
        // 优化：使用批量处理而不是map，减少内存分配和GC压力
        for (let i = 0; i < localMessages.length; i++) {
          formattedMessages[i] = formatTalkRecord(uid, localMessages[i])
        }
        
        // 更新缓存
        localDBCache.key = cacheKey
        localDBCache.data = formattedMessages
        localDBCache.timestamp = now
        
        // 批量添加记录
        dialogueStore.unshiftDialogueRecord(formattedMessages)
        
        // 设置加载状态为完成（3表示从本地数据库加载完成）
        loadConfig.status = 3
        
        // 恢复上传任务
        dialogueStore.restoreUploadTasks()
        
        // 使用requestAnimationFrame优化滚动性能
        requestAnimationFrame(() => {
          scrollToBottom()
        })
        
        const endTime = performance.now()
        console.log(`从本地数据库加载聊天记录耗时: ${(endTime - startTime).toFixed(2)}ms，加载了${localMessages.length}条记录`)
        
        return true
      }
      
      // 无数据时清除缓存
      localDBCache.key = ''
      localDBCache.data = null
      
      return false
    } catch (error) {
      console.error('从本地数据库加载聊天记录失败:', error)
      // 出错时清除缓存
      localDBCache.key = ''
      localDBCache.data = null
      return false
    }
  }

  /**
   * 加载数据主入口，支持指定消息定位模式
   * @param params 原有参数
   * @param options 可选，{ specifiedMsg } 指定消息对象
   */
  const onLoad = async (params: Params, options?: LoadOptions) => {
    // 使用性能标记测量加载时间
    const startTime = performance.now()
    
    // 检查会话是否变更，如果变更则重置配置
    if (
      params.talk_type !== loadConfig.talk_type ||
      params.receiver_id !== loadConfig.receiver_id
    ) {
      resetLoadConfig()
    }

    loadConfig.cursor = 0
    loadConfig.receiver_id = params.receiver_id
    loadConfig.talk_type = params.talk_type

    // 新增：支持指定消息定位模式，参数以传入为准合并
    if (options?.specifiedMsg?.cursor !== undefined) {
      // 特殊消息定位模式
      loadConfig.specialParams = { ...options.specifiedMsg } // 记录特殊参数，供分页加载用
      loadConfig.status = 0 // 复用主流程 loading 状态
      
      // 以 params 为基础，合并 specifiedMsg 的所有字段（只要有就覆盖）
      const contextParams = {
        ...params,
        ...options.specifiedMsg
      }
      //msg_id是用来做定位的，不做参数，所以这里清空
      contextParams.msg_id = ''
      
      // 使用Promise.all并行处理数据库操作和网络请求
      const serverDataPromise = ServeTalkRecords(contextParams)
      
      // 记录当前滚动高度
      const el = document.getElementById('imChatPanel')
      const scrollHeight = el?.scrollHeight || 0
      
      try {
        // 等待服务器响应
        const { data, code } = await serverDataPromise
        
        if (code !== 200) {
          loadConfig.status = 2
          return
        }
        
        console.log('data', data)
        
        // 优化：使用批量处理而不是map，减少内存分配
        const items = new Array(data.items?.length || 0)
        for (let i = 0; i < (data.items?.length || 0); i++) {
          items[i] = formatTalkRecord(uid, data.items[i])
        }
        
        // 根据方向和类型处理数据
        if (contextParams.direction === 'down' && !contextParams.type) {
          dialogueStore.clearDialogueRecord()
        }
        
        if (contextParams.type && contextParams.type === 'loadMore') {
          dialogueStore.addDialogueRecordForLoadMore(items)
        } else {
          dialogueStore.unshiftDialogueRecord(
            contextParams.direction === 'down' ? items : items.reverse()
          )
        }
        
        if (
          contextParams.direction === 'up' ||
          (contextParams.direction === 'down' && !contextParams.type)
        ) {
          loadConfig.status = items[0]?.sequence == 1 || data.length === 0 ? 2 : 1
        }
        
        loadConfig.cursor = data.cursor

        // 使用 requestAnimationFrame 来确保在下一帧渲染前设置滚动位置
        requestAnimationFrame(() => {
          const el = document.getElementById('imChatPanel')
          const msgId = options.specifiedMsg?.msg_id
          const target = msgId ? document.getElementById(msgId) : null

          if (el) {
            // 如果是向上加载更多，保持原有内容位置
            if (contextParams.direction === 'up') {
              el.scrollTop = el.scrollHeight - scrollHeight
            } else if (contextParams.type && contextParams.type === 'loadMore') {
              // 如果是向下加载更多，保持目标消息在可视区域底部
              // 使用可视区域高度来调整，而不是新内容的总高度
              requestAnimationFrame(() => { // 使用requestAnimationFrame替代nextTick
                if (el) {
                  el.scrollTop = scrollHeight - el.clientHeight
                }
              })
            } else if (target && msgId) {
              // 只有在有目标元素且有 msg_id 时才执行定位逻辑
              // 如果是定位到特定消息，计算并滚动到目标位置
              // 使用 requestAnimationFrame 确保 DOM 完全渲染后再计算位置
              requestAnimationFrame(() => {
                const el = document.getElementById('imChatPanel')
                const target = document.getElementById(msgId)

                if (el && target) {
                  loadConfig.isLocatingMessage = true

                  // 计算目标元素相对于容器的偏移量
                  const targetOffsetTop = target.offsetTop
                  const containerHeight = el.clientHeight
                  const targetHeight = target.offsetHeight

                  // 计算理想的滚动位置：让目标元素居中显示
                  let scrollTo = targetOffsetTop - containerHeight / 2 + targetHeight / 2

                  // 边界检查：确保目标元素完全在可视区域内
                  const minScrollTop = 0
                  const maxScrollTop = el.scrollHeight - containerHeight

                  // 如果计算出的位置超出边界，调整到边界内
                  if (scrollTo < minScrollTop) {
                    scrollTo = minScrollTop
                  } else if (scrollTo > maxScrollTop) {
                    scrollTo = maxScrollTop
                  }

                  // 执行滚动
                  el.scrollTo({ top: scrollTo, behavior: 'smooth' })

                  // 添加高亮边框
                  addClass(target, 'border')
                  setTimeout(() => removeClass(target, 'border'), 3000)

                  // 清除 dialogueStore 中的 specifiedMsg，避免重复使用
                  if (dialogueStore.specifiedMsg) {
                    dialogueStore.specifiedMsg = ''
                    dialogueStore.noRefreshRecords = true
                  }
                }
              })
            } else {
              // 其他情况滚动到底部
              // 在特殊参数模式下也需要恢复上传任务
              dialogueStore.restoreUploadTasks()
              scrollToBottom()
            }
          }
          
          const endTime = performance.now()
          console.log(`特殊消息定位模式加载耗时: ${(endTime - startTime).toFixed(2)}ms`)
        })
      } catch (error) {
        console.error('特殊消息定位模式加载失败:', error)
        loadConfig.status = 2
      }
      
      return
    }

    // 普通模式
    loadConfig.specialParams = undefined // 普通模式清空
    
    // 设置初始加载状态为0（加载中）
    loadConfig.status = 0
    
    // 使用Promise.all并行处理本地数据库加载和网络请求准备
    try {
      // 先从本地数据库加载数据
      const hasLocalData = await loadFromLocalDB(params)
      
      // 无论是否有本地数据，都从服务器获取最新数据
      console.log('onLoad()执行load')
      await load(params)
      
      const endTime = performance.now()
      console.log(`普通模式加载总耗时: ${(endTime - startTime).toFixed(2)}ms`)
    } catch (error) {
      console.error('加载聊天记录失败:', error)
      loadConfig.status = 2
    }
  }

  // 向上加载更多（兼容特殊参数模式）
  const onRefreshLoad = () => {
    if (loadConfig.status == 1 || loadConfig.status == 3) {
      console.log('specialParams', loadConfig.specialParams)
      // 判断是否是特殊参数模式
      if (loadConfig.specialParams && typeof loadConfig.specialParams === 'object') {
        // 检查特殊参数是否与当前会话匹配
        if (
          loadConfig.specialParams.talk_type === loadConfig.talk_type &&
          loadConfig.specialParams.receiver_id === loadConfig.receiver_id
        ) {
          // 特殊参数模式下，direction: 'up'，cursor: 当前最小 sequence
          // 注意：向上加载更多时，不传递 msg_id，避免触发定位逻辑
          onLoad(
            {
              receiver_id: loadConfig.receiver_id,
              talk_type: loadConfig.talk_type,
              limit: 30
            },
            {
              specifiedMsg: {
                ...loadConfig.specialParams,
                direction: 'up',
                sort_sequence: '',
                cursor: getMinSequence(),
                // 向上加载更多时不传递 msg_id，保持原有滚动位置
                msg_id: undefined
              }
            }
          )
        } else {
          // 如果不匹配，重置为普通模式
          resetLoadConfig()
          console.log('load执行2')
          load({
            receiver_id: loadConfig.receiver_id,
            talk_type: loadConfig.talk_type,
            limit: 30
          })
        }
      } else {
        // 原有逻辑
               console.log('load执行3')
        load({
          receiver_id: loadConfig.receiver_id,
          talk_type: loadConfig.talk_type,
          limit: 30
        })
      }
    }
  }

  // 向下加载更多（特殊参数模式才生效，普通模式无效，因为普通模式的数据就是从最新开始加载历史的，所以不需要加载更新的数据）
  const onLoadMoreDown = () => {
    // 判断是否是特殊参数模式
    if (loadConfig.specialParams && typeof loadConfig.specialParams === 'object') {
      if (loadConfig.isLocatingMessage) {
        loadConfig.isLocatingMessage = false
        return
      }
      // 添加时间间隔限制，至少间隔 500ms 才能触发下一次加载
      const now = Date.now()
      if (now - loadConfig.lastLoadMoreTime < 500) {
        return
      }
      loadConfig.lastLoadMoreTime = now

      // 记录当前目标消息的位置
      const el = document.getElementById('imChatPanel')
      if (el) {
        loadConfig.targetMessagePosition = el.scrollHeight - el.scrollTop
      }

      console.log('onLoadMoreDown 特殊模式触底了')
      // 检查特殊参数是否与当前会话匹配
      if (
        loadConfig.specialParams.talk_type === loadConfig.talk_type &&
        loadConfig.specialParams.receiver_id === loadConfig.receiver_id
      ) {
        onLoad(
          {
            receiver_id: loadConfig.receiver_id,
            talk_type: loadConfig.talk_type,
            limit: 30
          },
          {
            specifiedMsg: {
              ...loadConfig.specialParams,
              direction: 'down',
              sort_sequence: 'asc',
              cursor: getMaxSequence(),
              type: 'loadMore'
            }
          }
        )
      }
    }
  }

  return {
    loadConfig,
    records,
    onLoad,
    onRefreshLoad,
    onLoadMoreDown,
    onJumpMessage,
    resetLoadConfig
  }
}
