import { useState, useEffect, useRef, useCallback } from 'react'
import { Message } from '../types'
import { api } from '../services/api'
import { logger } from '../utils/logger'
import { formatApiMessageToMessage } from '../utils/formatMessage'
import { getSessionAvatar } from '../utils/avatarUtils'

/** silent：不显示会话加载态；失败时保留当前消息 */
export type RefreshMessagesOptions = { silent?: boolean }

export function useMessages(
  token: string,
  currentUserId: number | null,
  activeContactId: number | null,
  setContacts: React.Dispatch<React.SetStateAction<any[]>>
) {
  const [messages, setMessages] = useState<Record<number, Message[]>>({})
  const [loadedContacts, setLoadedContacts] = useState<Set<number>>(new Set())
  const [isLoadingMessages, setIsLoadingMessages] = useState(false)
  const [isLoadingMore, setIsLoadingMore] = useState(false)
  const [hasMoreMessages, setHasMoreMessages] = useState<Record<number, boolean>>({})
  const [uploadProgress, setUploadProgress] = useState<{ [key: string]: number }>({})
  const isLoadingMoreRef = useRef(false)

  // 退出登录或切换账号时清空内存中的会话消息，避免同一 contactId 跨账号串数据
  useEffect(() => {
    if (!token) {
      setMessages({})
      setLoadedContacts(new Set())
      setHasMoreMessages({})
      setUploadProgress({})
      isLoadingMoreRef.current = false
      setIsLoadingMessages(false)
      setIsLoadingMore(false)
      return
    }
    setMessages({})
    setLoadedContacts(new Set())
    setHasMoreMessages({})
    setUploadProgress({})
    isLoadingMoreRef.current = false
    setIsLoadingMore(false)
  }, [token, currentUserId])

  const formatMessageData = useCallback(
    (msg: any): Message => formatApiMessageToMessage(msg, currentUserId),
    [currentUserId]
  )

  // 拉取该会话最新一页；切换会话时也会调用，并与本地已加载的更早历史、未入库的本地消息合并
  const refreshMessages = useCallback(async (contactId: number, options?: RefreshMessagesOptions) => {
    if (!token) return

    const silent = options?.silent === true
    if (!silent) {
      setIsLoadingMessages(true)
    }
    try {
      const messagesData = await api.getMessages(token, contactId, {
        skip: 0,
        limit: 50
      })

      logger.info('App: Refreshed messages', { contactId, count: messagesData.length, silent })

      const formattedMessages: Message[] = messagesData.map(formatMessageData)
      formattedMessages.sort((a, b) => a.timestamp - b.timestamp)

      setMessages(prev => {
        const existing = prev[contactId] || []
        if (formattedMessages.length === 0) {
          return { ...prev, [contactId]: existing }
        }
        const serverIds = new Set(formattedMessages.map(m => m.id))
        const oldestFetched = formattedMessages[0].timestamp
        const preservedOlder = existing.filter(
          m => !serverIds.has(m.id) && m.timestamp < oldestFetched
        )
        const pendingLocal = existing.filter(
          m => !serverIds.has(m.id) && m.timestamp >= oldestFetched
        )
        const merged = [...preservedOlder, ...formattedMessages, ...pendingLocal].sort(
          (a, b) => a.timestamp - b.timestamp
        )
        return { ...prev, [contactId]: merged }
      })

      setHasMoreMessages(prev => ({
        ...prev,
        [contactId]: messagesData.length >= 50
      }))

      setLoadedContacts(prev => new Set(prev).add(contactId))
    } catch (error: unknown) {
      if (silent) {
        logger.warn('App: refresh messages skipped (silent)', {
          contactId,
          error: error instanceof Error ? error.message : String(error)
        })
      } else {
        logger.error('App: Failed to refresh messages', {
          contactId,
          error: error instanceof Error ? error.message : String(error)
        })
      }
    } finally {
      if (!silent) {
        setIsLoadingMessages(false)
      }
    }
  }, [token, formatMessageData])

  const fetchMoreMessages = useCallback(async (contactId: number) => {
    if (!token || isLoadingMoreRef.current || !hasMoreMessages[contactId]) return

    const currentMessages = messages[contactId] || []
    const skip = currentMessages.length

    isLoadingMoreRef.current = true
    setIsLoadingMore(true)
    try {
      const messagesData = await api.getMessages(token, contactId, {
        skip,
        limit: 50
      })

      logger.info('App: Fetched more messages', { contactId, skip, count: messagesData.length })

      setHasMoreMessages(prev => ({
        ...prev,
        [contactId]: messagesData.length >= 50
      }))

      if (messagesData.length === 0) return

      const formattedMessages: Message[] = messagesData.map(formatMessageData)
      formattedMessages.sort((a, b) => a.timestamp - b.timestamp)

      const existingIds = new Set(currentMessages.map(m => m.id))
      const newMessages = formattedMessages.filter(m => !existingIds.has(m.id))

      setMessages(prev => ({
        ...prev,
        [contactId]: [...newMessages, ...(prev[contactId] || [])]
      }))
    } catch (error: any) {
      logger.error('App: Failed to fetch more messages', { contactId, error: error.message })
    } finally {
      isLoadingMoreRef.current = false
      setIsLoadingMore(false)
    }
  }, [token, messages, hasMoreMessages, formatMessageData])

  // 发送文本消息
  const sendMessage = useCallback(async (content: string, contactId: number) => {
    if (!content.trim() || !contactId) return
    
    const tempMessageId = Date.now()
    const tempMessage: Message = {
      id: tempMessageId,
      content: content.trim(),
      isSelf: true,
      type: 'text',
      timestamp: Date.now()
    }

    setMessages(prev => ({
      ...prev,
      [contactId]: [...(prev[contactId] || []), tempMessage]
    }))

    setContacts(prev => prev.map(c => 
      c.id === contactId 
        ? { ...c, lastMessage: content.trim(), lastMessageTime: '刚刚' } 
        : c
    ))

    try {
      const response = await api.sendMessage(token, contactId, content.trim(), 'TEXT')
      logger.info('App: Message sent successfully', { content, receiverId: contactId, messageId: response.id })
      
      const realMessage = formatApiMessageToMessage(response, currentUserId)
      
      setMessages(prev => ({
        ...prev,
        [contactId]: (prev[contactId] || [])
          .filter(msg => msg.id !== tempMessageId)
          .concat(realMessage)
      }))
    } catch (error: any) {
      logger.error('App: Failed to send message', { error: error.message, receiverId: contactId })
      setMessages(prev => ({
        ...prev,
        [contactId]: (prev[contactId] || []).filter(msg => msg.id !== tempMessageId)
      }))
      throw error
    }
  }, [token, setContacts, currentUserId])

  // 发送文件消息
  const sendFileMessage = useCallback(async (file: File, contentType: 'IMAGE' | 'VIDEO' | 'FILE' = 'FILE', contactId: number) => {
    if (!contactId || !token) return
    
    const fileId = `${Date.now()}-${file.name}`
    
    try {
      setUploadProgress(prev => ({ ...prev, [fileId]: 0 }))
      
      const uploadResult = await api.uploadFile(
        token,
        file,
        (percent) => {
          setUploadProgress(prev => ({ ...prev, [fileId]: percent }))
        }
      )
      
      const messageResponse = await api.sendMessage(
        token,
        contactId,
        uploadResult.key,
        contentType,
        file.name
      )
      
      const newMessage: Message = {
        id: messageResponse.id,
        content: messageResponse.content,
        isSelf: true,
        type: contentType.toLowerCase() as 'image' | 'file' | 'video',
        timestamp: new Date(messageResponse.created_at).getTime(),
        title: messageResponse.title || file.name,
        content_type: contentType,
        size: uploadResult.size
      }
      
      setMessages(prev => ({
        ...prev,
        [contactId]: [...(prev[contactId] || []), newMessage]
      }))
      
      setUploadProgress(prev => {
        const newProgress = { ...prev }
        delete newProgress[fileId]
        return newProgress
      })
      
      logger.info('File message sent', { messageId: messageResponse.id, contentType })
    } catch (error: any) {
      logger.error('Send file message failed', error)
      setUploadProgress(prev => {
        const newProgress = { ...prev }
        delete newProgress[fileId]
        return newProgress
      })
      throw error
    }
  }, [token])

  const previewForForwardedMessage = useCallback((msg: Message): string => {
    if (msg.type === 'image') return '[图片]'
    if (msg.type === 'video') return '[视频]'
    if (msg.type === 'file') return msg.title || '[文件]'
    if (msg.type === 'notification') {
      if (msg.content_type === 'USER_NOTIFICATION' && msg.title) {
        return msg.title
      }
      return [msg.title, msg.content].filter(Boolean).join(' ') || msg.content
    }
    return msg.content || ''
  }, [])

  const forwardMessage = useCallback(
    async (msg: Message, receiverIds: number[]) => {
      if (!token) return
      const unique = [...new Set(receiverIds)].filter(id => id > 0)
      if (unique.length === 0) return

      const lastPreview = previewForForwardedMessage(msg)

      const updateContactRow = (contactId: number) => {
        setContacts(prev => {
          const has = prev.some(c => c.id === contactId)
          if (has) {
            return prev.map(c =>
              c.id === contactId
                ? { ...c, lastMessage: lastPreview, lastMessageTime: '刚刚', lastMessageAt: Date.now() }
                : c
            )
          }
          return [
            ...prev,
            {
              id: contactId,
              name: `用户${contactId}`,
              avatar: getSessionAvatar(contactId, `用户${contactId}`, 40),
              lastMessage: lastPreview,
              lastMessageTime: '刚刚',
              lastMessageAt: Date.now(),
              unreadCount: 0,
              remarks: null
            }
          ]
        })
      }

      for (const contactId of unique) {
        const tempMessageId = Date.now() + Math.floor(Math.random() * 1e9)

        if (msg.content_type === 'USER_NOTIFICATION' && msg.type === 'notification') {
          const tempMessage: Message = {
            id: tempMessageId,
            content: msg.content,
            isSelf: true,
            type: 'notification',
            timestamp: Date.now(),
            title: msg.title,
            actionUrl: msg.actionUrl,
            actionText: msg.actionText,
            content_type: 'USER_NOTIFICATION',
            app_id: msg.app_id
          }
          setMessages(prev => ({
            ...prev,
            [contactId]: [...(prev[contactId] || []), tempMessage]
          }))
          updateContactRow(contactId)
          try {
            const response = await api.sendUserNotificationMessage(token, {
              receiverId: contactId,
              title: msg.title || '通知',
              content: msg.content,
              actionUrl: msg.actionUrl,
              actionText: msg.actionText,
              appId: msg.app_id
            })
            const realMessage = formatApiMessageToMessage(response, currentUserId)
            setMessages(prev => ({
              ...prev,
              [contactId]: (prev[contactId] || [])
                .filter(m => m.id !== tempMessageId)
                .concat(realMessage)
            }))
          } catch (error: unknown) {
            logger.error('App: forward USER_NOTIFICATION failed', { contactId, error })
            setMessages(prev => ({
              ...prev,
              [contactId]: (prev[contactId] || []).filter(m => m.id !== tempMessageId)
            }))
            throw error
          }
          continue
        }

        if (msg.type === 'notification') {
          const text = [msg.title, msg.content].filter(Boolean).join('\n') || msg.content
          if (!text.trim()) {
            continue
          }
          const tempMessage: Message = {
            id: tempMessageId,
            content: text.trim(),
            isSelf: true,
            type: 'text',
            timestamp: Date.now()
          }
          setMessages(prev => ({
            ...prev,
            [contactId]: [...(prev[contactId] || []), tempMessage]
          }))
          updateContactRow(contactId)
          try {
            const response = await api.sendMessage(token, contactId, text.trim(), 'TEXT')
            const realMessage = formatApiMessageToMessage(response, currentUserId)
            setMessages(prev => ({
              ...prev,
              [contactId]: (prev[contactId] || [])
                .filter(m => m.id !== tempMessageId)
                .concat(realMessage)
            }))
          } catch (error: unknown) {
            logger.error('App: forward notification as TEXT failed', { contactId, error })
            setMessages(prev => ({
              ...prev,
              [contactId]: (prev[contactId] || []).filter(m => m.id !== tempMessageId)
            }))
            throw error
          }
          continue
        }

        if (msg.type === 'text') {
          const text = (msg.content || '').trim()
          if (!text) continue
          const tempMessage: Message = {
            id: tempMessageId,
            content: text,
            isSelf: true,
            type: 'text',
            timestamp: Date.now()
          }
          setMessages(prev => ({
            ...prev,
            [contactId]: [...(prev[contactId] || []), tempMessage]
          }))
          updateContactRow(contactId)
          try {
            const response = await api.sendMessage(token, contactId, text, 'TEXT')
            const realMessage = formatApiMessageToMessage(response, currentUserId)
            setMessages(prev => ({
              ...prev,
              [contactId]: (prev[contactId] || [])
                .filter(m => m.id !== tempMessageId)
                .concat(realMessage)
            }))
          } catch (error: unknown) {
            logger.error('App: forward text failed', { contactId, error })
            setMessages(prev => ({
              ...prev,
              [contactId]: (prev[contactId] || []).filter(m => m.id !== tempMessageId)
            }))
            throw error
          }
          continue
        }

        if (msg.type === 'image' || msg.type === 'video' || msg.type === 'file') {
          const contentType = (msg.type === 'image' ? 'IMAGE' : msg.type === 'video' ? 'VIDEO' : 'FILE') as
            | 'IMAGE'
            | 'VIDEO'
            | 'FILE'
          const content = msg.content
          if (!content) {
            logger.warn('App: forward media skipped, empty content', { type: msg.type })
            continue
          }
          const title = msg.title || '私信'
          const tempMessage: Message = {
            id: tempMessageId,
            content,
            isSelf: true,
            type: msg.type,
            timestamp: Date.now(),
            title,
            content_type: contentType,
            size: msg.size
          }
          setMessages(prev => ({
            ...prev,
            [contactId]: [...(prev[contactId] || []), tempMessage]
          }))
          updateContactRow(contactId)
          try {
            const response = await api.sendMessage(token, contactId, content, contentType, title)
            const realMessage = formatApiMessageToMessage(response, currentUserId)
            setMessages(prev => ({
              ...prev,
              [contactId]: (prev[contactId] || [])
                .filter(m => m.id !== tempMessageId)
                .concat(realMessage)
            }))
          } catch (error: unknown) {
            logger.error('App: forward media failed', { contactId, error })
            setMessages(prev => ({
              ...prev,
              [contactId]: (prev[contactId] || []).filter(m => m.id !== tempMessageId)
            }))
            throw error
          }
          continue
        }

        logger.warn('App: forwardMessage unsupported message', { type: msg.type, content_type: msg.content_type })
      }
    },
    [token, setContacts, currentUserId, previewForForwardedMessage]
  )

  // 切换到某个会话时同步托盘：清除该会话在托盘未读列表中的展示（服务端已读由点击会话时 read-all 处理）
  useEffect(() => {
    if (activeContactId && window.electron?.ipcRenderer) {
      window.electron.ipcRenderer.send('clear-unread', activeContactId)
    }
  }, [activeContactId])

  // 切换联系人时重新拉取该会话最新消息（含再次进入已打开过的会话）
  useEffect(() => {
    if (activeContactId && token) {
      void refreshMessages(activeContactId)
    }
  }, [activeContactId, token, refreshMessages])

  return {
    messages,
    setMessages,
    isLoadingMessages,
    isLoadingMore,
    hasMoreMessages,
    uploadProgress,
    sendMessage,
    sendFileMessage,
    forwardMessage,
    fetchMessages: refreshMessages,
    fetchMoreMessages,
    loadedContacts
  }
}
