import V2NIM, { V2NIMConst } from 'nim-web-sdk-ng'
import { createContext, useCallback, useEffect, useRef } from 'react'
import {
  msgListAtom,
  ExtendedMessage,
  isWaitingForReplyAtom,
  MessageLikeStatus,
  MessageServerExtension,
  parseMessageServerExtension,
  stringifyMessageServerExtension,
  selectedConversationIdAtom,
  isCoinInsufficientAtom,
  isCallAtom,
} from '@/atoms/im'
import { useAtom, useSetAtom, useAtomValue } from 'jotai'
import {
  V2NIMMessage,
  V2NIMMessageListOption,
} from 'nim-web-sdk-ng/dist/v2/NIM_BROWSER_SDK/V2NIMMessageService'
import { V2NIMError } from 'nim-web-sdk-ng/dist/v2/NIM_BROWSER_SDK/types'
import { CustomMessageType } from '@/types/im'
import { useQueryClient } from '@tanstack/react-query'
import { imKeys, walletKeys } from '@/lib/query-keys'
import { AiUserImBaseInfoOutput } from '@/services/im'
import { useAudioPlayer, UseAudioPlayerReturn } from '@/hooks/useAudioPlayer'
import { playVoiceAtom } from '@/atoms/chat'
import { useVoiceTTS } from '@/hooks/useVoiceTTS'
import { extractTextForVoice } from '@/utils/textParser'
import { NIMMessageSendError } from '@/types/api'

const FAILED_MSG_STORAGE_KEY = 'nim_failed_messages'

type StoredFailedMessage = {
  conversationId: string
  message: V2NIMMessage
  reason: 'coinInsufficient'
  timestamp: number
  loginUserId: string
}

const readStoredFailedMessages = (): StoredFailedMessage[] => {
  if (typeof window === 'undefined') return []
  try {
    const raw = window.localStorage.getItem(FAILED_MSG_STORAGE_KEY)
    if (!raw) return []
    const parsed = JSON.parse(raw)
    if (!Array.isArray(parsed)) return []
    return parsed
  } catch (error) {
    console.error('读取失败消息缓存失败', error)
    return []
  }
}

const writeStoredFailedMessages = (records: StoredFailedMessage[]) => {
  if (typeof window === 'undefined') return
  try {
    window.localStorage.setItem(FAILED_MSG_STORAGE_KEY, JSON.stringify(records))
  } catch (error) {
    console.error('写入失败消息缓存失败', error)
  }
}

const NimMsgContext = createContext({
  addMsg: (conversationId: string, messages: V2NIMMessage[], isNewMessage?: boolean) => {},
  sendMessageActive: ({
    conversationId,
    msg,
    isLoading,
  }: {
    conversationId: string
    msg: V2NIMMessage
    isLoading?: boolean
  }) => {},
  getHistoryMsgActive: ({
    conversationId,
    endTime,
    lastMsgId,
    limit,
  }: {
    conversationId: string
    endTime: number
    lastMsgId?: string
    limit?: number
  }) => {},
  addLoadingMessage: (conversationId: string) => {},
  removeLoadingMessage: (conversationId: string) => {},
  updateMessageLikeStatus: (targetMessage: ExtendedMessage, likeStatus: MessageLikeStatus) => {},
  audioPlayer: undefined as UseAudioPlayerReturn | undefined,
  clearHistoryMessage: (conversationId: string) => {},
})

export const NimMsgProvider = ({ children, nim }: { children: React.ReactNode; nim: V2NIM }) => {
  const setMsgList = useSetAtom(msgListAtom)
  const setIsWaitingForReply = useSetAtom(isWaitingForReplyAtom)
  const queryClient = useQueryClient()
  const audioPlayer = useAudioPlayer()
  const playVoice = useAtomValue(playVoiceAtom)
  const selectedConversationId = useAtomValue(selectedConversationIdAtom)
  const setIsCoinInsufficient = useSetAtom(isCoinInsufficientAtom)
  const setIsCall = useSetAtom(isCallAtom)
  const loginUserId = nim.V2NIMLoginService.getLoginUser()
  const pendingFailedMessagesRef = useRef(new Map<string, V2NIMMessage[]>())

  const { isGenerating, generateAudioUrl } = useVoiceTTS({
    cacheEnabled: true,
  })

  const persistFailedMessage = useCallback(
    (conversationId: string, message: V2NIMMessage) => {
      if (typeof window === 'undefined' || !message?.messageClientId || !loginUserId) return
      const nextRecord: StoredFailedMessage = {
        conversationId,
        message: {
          ...message,
          conversationId,
          sendingState: 2,
        },
        reason: 'coinInsufficient',
        timestamp: Date.now(),
        loginUserId,
      }
      const existing = readStoredFailedMessages().filter((record) => {
        if (!record.message?.messageClientId) return false
        if (record.loginUserId !== loginUserId) return true
        return record.message.messageClientId !== message.messageClientId
      })
      writeStoredFailedMessages([...existing, nextRecord])
    },
    [loginUserId]
  )

  const removePersistedFailedMessage = useCallback(
    (messageClientId?: string) => {
      if (typeof window === 'undefined' || !messageClientId || !loginUserId) return
      const filtered = readStoredFailedMessages().filter((record) => {
        if (!record.message?.messageClientId) return false
        if (record.loginUserId !== loginUserId) return true
        return record.message.messageClientId !== messageClientId
      })
      writeStoredFailedMessages(filtered)

      pendingFailedMessagesRef.current.forEach((messages, conversationId) => {
        const nextMessages = messages.filter(
          (message) => message.messageClientId !== messageClientId
        )
        if (nextMessages.length === 0) {
          pendingFailedMessagesRef.current.delete(conversationId)
        } else {
          pendingFailedMessagesRef.current.set(conversationId, nextMessages)
        }
      })
    },
    [loginUserId]
  )

  // addMsg 函数需要先声明
  const addMsg = useCallback(
    (conversationId: string, messages: V2NIMMessage[], isNewMessage = false) => {
      const sortFunc = (a: ExtendedMessage, b: ExtendedMessage) => {
        return a.createTime - b.createTime
      }

      setMsgList((prev) => {
        // 使用 clone 方法创建新的 QueueMap 实例以确保状态更新
        const newMsgList = prev.clone()

        // 从当前状态中获取已有消息（而不是从闭包中的 msgList）
        const _msgs = newMsgList.get(conversationId) || []

        // 处理新消息
        messages
          .filter((msg) => !!msg.messageClientId)
          .forEach((msg) => {
            const newMsg: ExtendedMessage = {
              ...msg,
              isNewMessage: isNewMessage,
            }
            const _msg = _msgs.find((m) => m.messageClientId === msg.messageClientId)

            if (_msg) {
              if (_msg.createTime <= newMsg.createTime || _msg.sendingState === 3) {
                _msgs.splice(_msgs.indexOf(_msg), 1, newMsg)
              }
            } else {
              _msgs.push(newMsg)
            }
          })

        // 排序并设置消息
        const sortedMsgs = [..._msgs].sort(sortFunc)
        newMsgList.set(conversationId, sortedMsgs, false)

        return newMsgList
      })
    },
    [setMsgList]
  ) // 移除 msgList 依赖，避免闭包问题

  const flushPendingFailedMessages = useCallback(
    (conversationId: string) => {
      const pending = pendingFailedMessagesRef.current.get(conversationId)
      if (!pending || pending.length === 0) return
      addMsg(
        conversationId,
        pending.map((message) => ({
          ...message,
          sendingState: 2,
        })),
        false
      )
      pendingFailedMessagesRef.current.delete(conversationId)
    },
    [addMsg]
  )

  useEffect(() => {
    if (!loginUserId) return
    const stored = readStoredFailedMessages().filter((record) => record.loginUserId === loginUserId)
    const grouped = new Map<string, V2NIMMessage[]>()
    stored.forEach((record) => {
      const list = grouped.get(record.conversationId) || []
      list.push({
        ...record.message,
        sendingState: 2,
      })
      grouped.set(record.conversationId, list)
    })
    pendingFailedMessagesRef.current = grouped
  }, [loginUserId])

  const removeMsg = useCallback(
    (conversationId: string, messageClientId: string) => {
      setMsgList((prev) => {
        const newMsgList = prev.clone()
        const messages = newMsgList.get(conversationId) || []
        const filteredMessages = messages.filter((msg) => msg.messageClientId !== messageClientId)
        newMsgList.set(conversationId, filteredMessages, false)
        return newMsgList
      })
    },
    [setMsgList]
  )

  // 添加loading消息
  const addLoadingMessage = useCallback(
    (conversationId: string) => {
      setMsgList((prev) => {
        const newMsgList = prev.clone()
        const messages = newMsgList.get(conversationId) || []
        // 移除已存在的loading消息，避免重复
        const filteredMessages = messages.filter((msg) => !msg.isLoadingMessage)

        const loadingMessage: ExtendedMessage = {
          messageClientId: `loading_${Date.now()}`,
          messageServerId: '',
          conversationId: conversationId,
          conversationType: 1, // P2P聊天
          senderId: '',
          receiverId: '',
          createTime: Date.now(),
          messageType: 0, // 文本消息类型
          text: '',
          attachment: undefined,
          sendingState: 1,
          messageStatus: 0 as any,
          isSelf: false,
          isLoadingMessage: true,
          isNewMessage: false,
        }

        // 添加loading消息（渲染时会单独处理显示顺序）
        filteredMessages.push(loadingMessage)
        newMsgList.set(conversationId, filteredMessages, false)
        return newMsgList
      })
    },
    [setMsgList]
  )

  // 移除loading消息
  const removeLoadingMessage = useCallback(
    (conversationId: string) => {
      setMsgList((prev) => {
        const newMsgList = prev.clone()
        const messages = newMsgList.get(conversationId) || []
        const filteredMessages = messages.filter((msg) => !msg.isLoadingMessage)
        newMsgList.set(conversationId, filteredMessages, false)
        return newMsgList
      })
    },
    [setMsgList]
  )

  useEffect(() => {
    const handleMsgReceived = (messages: V2NIMMessage[]) => {
      // 只在新消息时处理
      if (messages.length > 1) {
        return
      }

      console.log('handleMsgReceived', messages)
      messages.forEach(async (msg) => {
        let needSendWaiting = false
        // 自动播放语音消息 - 只有当消息来自当前打开的会话时才播放
        if (
          msg.messageType === 0 &&
          !msg.isSelf &&
          playVoice.isAutoPlayVoice &&
          msg.conversationId === selectedConversationId
        ) {
          const audioText = extractTextForVoice(msg.text || '')
          if (audioText) {
            const audioUrl = await generateAudioUrl({
              text: audioText,
              voiceType: playVoice.voiceType,
              speechRate: playVoice.dialogueSpeechRate,
              pitchRate: playVoice.dialoguePitch,
            })
            audioPlayer?.play(msg.messageClientId, audioUrl)
          }
        }

        // 自定义消息
        if (msg.messageType === 100) {
          const { attachment } = msg || {}
          const { raw } = attachment || {}
          const customData = JSON.parse(raw || '{}')

          // 自己发送的礼物消息
          if (customData.type === CustomMessageType.IM_SEND_GIFT && msg.isSelf) {
            needSendWaiting = true
          }

          if (customData.type === CustomMessageType.INSUFFICIENT_BALANCE) {
            const event = new CustomEvent('call-coin-insufficient')
            window.dispatchEvent(event)
            return
          }

          // 等级升级消息
          if (customData.type === CustomMessageType.HEARTBEAT_LEVEL_UP) {
            // 发送等级升级事件通知
            const levelUpResult = {
              detail: {
                type: 'up',
                aiId: msg.senderId.split('@')[0],
                newLevel: customData.heartbeatLevel,
                title: customData.title,
                heartbeatVal: customData.heartbeatVal,
              },
            }
            const levelUpEvent = new CustomEvent('heartbeat-level-change', levelUpResult)
            window.dispatchEvent(levelUpEvent)
            const levelUpTopEvent = new CustomEvent('heartbeat-level-change-top', levelUpResult)
            window.dispatchEvent(levelUpTopEvent)
            queryClient.setQueryData(
              imKeys.imUserInfo(Number(msg.senderId.split('@')[0])),
              (old: AiUserImBaseInfoOutput) => {
                if (!old)
                  return {
                    aiUserHeartbeatRelation: {
                      title: customData.title,
                      heartbeatLevel: customData.heartbeatLevel,
                      heartbeatLevelName: customData.heartbeatLevelName,
                      heartbeatLevelNum: customData.heartbeatLevelNum,
                      heartbeatVal: customData.heartbeatVal,
                    },
                  }
                return {
                  ...old,
                  aiUserHeartbeatRelation: {
                    ...old?.aiUserHeartbeatRelation,
                    title: customData.title,
                    heartbeatLevel: customData.heartbeatLevel,
                    heartbeatLevelName: customData.heartbeatLevelName,
                    heartbeatLevelNum: customData.heartbeatLevelNum,
                    heartbeatVal: customData.heartbeatVal,
                  },
                }
              }
            )
            return
          }

          // 等级降级消息
          if (customData.type === CustomMessageType.HEARTBEAT_LEVEL_DOWN) {
            // 发送等级降级事件通知
            const levelDownResult = {
              detail: {
                type: 'down',
                aiId: msg.senderId.split('@')[0],
                title: customData.title,
                newLevel: customData.heartbeatLevel,
                heartbeatVal: customData.heartbeatVal,
              },
            }
            const levelDownEvent = new CustomEvent('heartbeat-level-change', levelDownResult)
            window.dispatchEvent(levelDownEvent)
            const levelDownTopEvent = new CustomEvent('heartbeat-level-change-top', levelDownResult)
            window.dispatchEvent(levelDownTopEvent)

            queryClient.setQueryData(
              imKeys.imUserInfo(Number(msg.senderId.split('@')[0])),
              (old: AiUserImBaseInfoOutput) => {
                if (!old)
                  return {
                    aiUserHeartbeatRelation: {
                      title: customData.title,
                      heartbeatLevel: customData.heartbeatLevel,
                      heartbeatLevelName: customData.heartbeatLevelName,
                      heartbeatLevelNum: customData.heartbeatLevelNum,
                      heartbeatVal: customData.heartbeatVal,
                    },
                  }
                return {
                  ...old,
                  aiUserHeartbeatRelation: {
                    ...old?.aiUserHeartbeatRelation,
                    heartbeatLevel: customData.heartbeatLevel,
                    heartbeatLevelName: customData.heartbeatLevelName,
                    heartbeatLevelNum: customData.heartbeatLevelNum,
                    heartbeatVal: customData.heartbeatVal,
                  },
                }
              }
            )
            return
          }
        }

        if (!msg.isSelf) {
          try {
            // 每条消息计算心动值
            const { score }: { score: number } = JSON.parse(msg.serverExtension || '{}')
            queryClient.setQueryData(
              imKeys.imUserInfo(Number(msg.senderId.split('@')[0])),
              (old: AiUserImBaseInfoOutput) => {
                if (!old) {
                  return old
                }
                if (score) {
                  return {
                    ...old,
                    aiUserHeartbeatRelation: {
                      ...(old.aiUserHeartbeatRelation || {}),
                      heartbeatVal: Number(
                        ((old.aiUserHeartbeatRelation?.heartbeatVal || 0) + (score || 0)).toFixed(1)
                      ),
                    },
                  }
                }
                return {
                  ...old,
                  aiUserHeartbeatRelation: {
                    ...old.aiUserHeartbeatRelation,
                    heartbeatVal: Number(
                      ((old.aiUserHeartbeatRelation?.heartbeatVal || 0) + (score || 0)).toFixed(1)
                    ),
                  },
                }
              }
            )
          } catch (error) {
            console.log('error', error)
          }
        }

        // 如果是用户自己发送的礼物消息，需要继续等待AI回复
        if (needSendWaiting) {
          // 设置等待回复状态并添加loading消息
          setIsWaitingForReply(true)
          addLoadingMessage(msg.conversationId)
        } else {
          // 其他消息移除loading消息并设置不再等待回复
          removeLoadingMessage(msg.conversationId)
          setIsWaitingForReply(false)
        }

        // 新收到的消息标记为需要打字效果
        addMsg(msg.conversationId, [msg], true)
      })
    }
    const handleMsgModified = (messages: V2NIMMessage[]) => {
      messages.forEach((msg) => {
        addMsg(msg.conversationId, [msg], false)
      })
    }
    nim.V2NIMMessageService.on('onReceiveMessages', handleMsgReceived)
    nim.V2NIMMessageService.on('onReceiveMessagesModified', handleMsgModified)

    // 添加测试事件监听器
    const handleTestMessage = (event: CustomEvent) => {
      const { messages } = event.detail
      if (messages && Array.isArray(messages)) {
        handleMsgReceived(messages)
      }
    }

    window.addEventListener('nim-message-received', handleTestMessage as EventListener)

    // window.mockMessage = () => {
    //   const message = nim.V2NIMMessageCreator.createTextMessage('test');
    //   message.senderId = '4419183024168961' + Date.now();
    //   message.receiverId = 'test' + Date.now();
    //   message.conversationId = selectedConversationId || '';
    //   message.messageType = 100;
    //   message.createTime = Date.now();
    //   message.sendingState = 0;
    //   message.messageClientId = 'test' + Date.now();
    //   message.messageServerId = 'test' + Date.now();
    //   message.serverExtension = '{}';
    //   message.attachment = {
    //     raw: JSON.stringify({
    //       type: CustomMessageType.IMAGE,
    //       width: '1440',
    //       height: '2560',
    //       url: 'https://hhb.crushlevel.ai/dev/role/17581021489486439.jpg',
    //       unlockPrice: 0,
    //     })
    //   }
    //   handleMsgReceived([message]);
    // }

    return () => {
      nim.V2NIMMessageService.off('onReceiveMessages', handleMsgReceived)
      window.removeEventListener('nim-message-received', handleTestMessage as EventListener)
    }
  }, [
    addMsg,
    removeLoadingMessage,
    setIsWaitingForReply,
    playVoice,
    generateAudioUrl,
    audioPlayer,
    selectedConversationId,
  ])

  const getMsg = useCallback(
    (conversationId: string, idClients: string[]): ExtendedMessage[] => {
      // 这个函数将在 getHistoryMsgActive 中通过闭包访问最新的 msgList
      // 我们需要确保它能获取到最新状态
      let msgs: ExtendedMessage[] = []

      setMsgList((prev) => {
        msgs = prev.get(conversationId) || []
        return prev // 不修改状态，只是读取
      })

      console.log('getMsg 调用:', {
        conversationId,
        idClients,
        foundMsgCount: msgs.length,
      })

      if (idClients.length === 0) {
        return msgs
      }
      return msgs.filter((msg) => idClients.includes(msg.messageClientId))
    },
    [setMsgList]
  )

  const sendMessageActive = useCallback(
    async ({
      msg,
      conversationId,
      isLoading = true,
    }: {
      msg: V2NIMMessage
      conversationId: string
      isLoading?: boolean
    }) => {
      const newMsg = { ...msg }
      newMsg.senderId = nim.V2NIMLoginService.getLoginUser()
      newMsg.receiverId = nim.V2NIMConversationIdUtil.parseConversationTargetId(conversationId)
      newMsg.conversationId = conversationId
      newMsg.createTime = newMsg.createTime || Date.now()
      newMsg.sendingState = 3
      removePersistedFailedMessage(newMsg.messageClientId)

      // 发送消息
      try {
        addMsg(conversationId, [newMsg], false) // 发送的消息不需要打字效果

        if (isLoading) {
          // 设置等待回复状态并添加loading消息
          setIsWaitingForReply(true)
          addLoadingMessage(conversationId)
        }

        const { message } = await nim.V2NIMMessageService.sendMessage(newMsg, conversationId)
        if (message && message.conversationId) {
          addMsg(message.conversationId, [message], false) // 发送成功的消息也不需要打字效果
          removePersistedFailedMessage(message.messageClientId)
        }
      } catch (error) {
        console.log('sendMessage error:', error, JSON.stringify(error))
        if (isLoading) {
          // 发送失败时移除loading状态
          setIsWaitingForReply(false)
          removeLoadingMessage(conversationId)
        }

        // 将 V2NIMError 转换为 NIMMessageSendError 以便统一处理
        let nimError: NIMMessageSendError
        if (error instanceof NIMMessageSendError) {
          nimError = error
        } else {
          nimError = NIMMessageSendError.fromV2NIMError(error)
        }

        // 钻石不足错误处理
        if (nimError.code === 20000) {
          setIsCoinInsufficient(true)
          // // 删除消息
          // removeMsg(conversationId, newMsg.messageClientId);
          queryClient.invalidateQueries({ queryKey: walletKeys.getWalletBalance() })
          persistFailedMessage(conversationId, {
            ...newMsg,
            sendingState: 2,
          })
          // return;
        }

        // 其他错误，更新消息状态为发送失败
        newMsg.sendingState = 2
        addMsg(
          conversationId,
          [
            {
              ...newMsg,
              sendingState: 2,
            },
          ],
          false
        ) // 发送失败的消息不需要打字效果
      }
    },
    [
      addMsg,
      addLoadingMessage,
      removeLoadingMessage,
      setIsWaitingForReply,
      removePersistedFailedMessage,
      setIsCoinInsufficient,
      queryClient,
      persistFailedMessage,
    ]
  )

  const getHistoryMsgActive = useCallback(
    async ({
      conversationId,
      endTime,
      lastMsgId,
      limit = 100,
    }: {
      conversationId: string
      endTime: number
      lastMsgId?: string
      limit?: number
    }) => {
      const finalParams: V2NIMMessageListOption = {
        conversationId,
        endTime,
        limit,
      }

      if (lastMsgId) {
        const anchorMessage = getMsg(conversationId, [lastMsgId])[0]
        if (anchorMessage) {
          finalParams.anchorMessage = anchorMessage
          console.log('getHistoryMsgActive 找到锚点消息:', anchorMessage.messageClientId)
        } else {
          console.log('getHistoryMsgActive 未找到锚点消息:', lastMsgId)
        }
      }

      const msgs = await nim.V2NIMMessageService.getMessageList(finalParams)
      console.log('🔥 getHistoryMsgActive 获取到消息:', {
        conversationId,
        requestedLimit: limit,
        actualMsgCount: msgs.length,
        msgs: msgs.map((m) => ({ id: m.messageClientId, text: m.text, createTime: m.createTime })),
      })

      addMsg(conversationId, msgs, false) // 历史消息不需要打字效果
      flushPendingFailedMessages(conversationId)
    },
    [getMsg, addMsg, flushPendingFailedMessages]
  )

  // 更新消息点赞状态 - 使用NIM SDK的modifyMessage API
  const updateMessageLikeStatus = useCallback(
    async (targetMessage: ExtendedMessage, likeStatus: MessageLikeStatus) => {
      console.log('updateMessageLikeStatus', targetMessage, likeStatus)
      try {
        // 解析当前的serverExtension
        const currentServerExt = parseMessageServerExtension(
          (targetMessage as V2NIMMessage).serverExtension
        )
        // 构造新的serverExtension - 简化版，只存储用户的点赞状态
        const newServerExt: MessageServerExtension = {
          ...currentServerExt,
        }
        // 更新用户的点赞状态
        if (likeStatus === MessageLikeStatus.None) {
          delete newServerExt.likeStatus // 移除点赞状态
        } else {
          newServerExt.likeStatus = likeStatus
        }
        // 调用NIM SDK的modifyMessage API
        const modifyResult = await nim.V2NIMMessageService.modifyMessage(targetMessage, {
          serverExtension: stringifyMessageServerExtension(newServerExt),
        })
        console.log('消息点赞状态更新成功:', modifyResult)
        // 更新本地状态
        if (modifyResult.message) {
          addMsg(targetMessage.conversationId, [modifyResult.message], false)
        }
      } catch (error) {
        console.error('更新消息点赞状态失败:', JSON.stringify(error))
        // TODO: 可以在这里添加错误提示给用户
      }
    },
    [addMsg]
  )

  const clearHistoryMessage = useCallback(
    async (conversationId: string) => {
      console.log('clearHistoryMessage', conversationId)
      try {
        await nim.V2NIMMessageService.clearHistoryMessage({
          conversationId,
          deleteRoam: true,
          onlineSync: true,
          clearMode: 0,
        })
        setMsgList((prev) => {
          const newMsgList = prev.clone()
          newMsgList.delete(conversationId)
          return newMsgList
        })
      } catch (error) {
        console.error('删除消息失败:', JSON.stringify(error))
      }
    },
    [setMsgList]
  )

  return (
    <NimMsgContext.Provider
      value={{
        addMsg,
        sendMessageActive,
        getHistoryMsgActive,
        addLoadingMessage,
        removeLoadingMessage,
        updateMessageLikeStatus,
        audioPlayer,
        clearHistoryMessage,
      }}
    >
      {children}
    </NimMsgContext.Provider>
  )
}

export default NimMsgContext
