import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import api from '@/utils/request'

type MessageCallback = (msg: any) => void
const listeners = new Set<MessageCallback>()

export function onNewMessage(cb: MessageCallback): () => void {
  listeners.add(cb)
  return () => { listeners.delete(cb) }
}

export const useMessageStore = defineStore('message', () => {
  const currentOpenChatId = ref<number | null>(null)
  const wsConnected = ref(false)
  /** 来自 GET /messages/unread-count，供侧边栏角标使用 */
  const serverUnreadTotal = ref(0)

  let ws: WebSocket | null = null
  let heartbeatTimer: ReturnType<typeof setInterval> | null = null
  let reconnectTimer: ReturnType<typeof setTimeout> | null = null
  let unreadFetchTimer: ReturnType<typeof setTimeout> | null = null

  const totalUnread = computed(() => serverUnreadTotal.value)

  async function fetchUnreadCount() {
    try {
      const res = await api.get('/messages/unread-count')
      const n = res.data
      serverUnreadTotal.value = typeof n === 'number' ? n : Number(n)
    } catch (e) {
      console.error(e)
    }
  }

  /** WS 推送可能连发，合并为一次 HTTP 查询 */
  function scheduleFetchUnreadCount() {
    if (unreadFetchTimer) clearTimeout(unreadFetchTimer)
    unreadFetchTimer = setTimeout(() => {
      unreadFetchTimer = null
      fetchUnreadCount()
    }, 300)
  }

  function initWebSocket() {
    if (ws && ws.readyState <= WebSocket.OPEN) return

    if (reconnectTimer) {
      clearTimeout(reconnectTimer)
      reconnectTimer = null
    }

    const token = localStorage.getItem('token')
    if (!token) return

    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
    const wsUrl = `${protocol}//${window.location.host}/api/v1/ws/messages?token=${token}`

    ws = new WebSocket(wsUrl)

    ws.onopen = () => {
      wsConnected.value = true
      fetchUnreadCount()
      heartbeatTimer = setInterval(() => {
        if (ws && ws.readyState === WebSocket.OPEN) ws.send('ping')
      }, 30000)
    }

    ws.onmessage = (event) => {
      if (event.data === 'pong') return
      try {
        const parsed = JSON.parse(event.data)
        if (parsed.type === 'NEW_MESSAGE') {
          handleNewMessage(parsed.data)
        }
      } catch (e) {
        console.error('WS parse error', e)
      }
    }

    ws.onclose = () => {
      wsConnected.value = false
      cleanupTimers()
      reconnectTimer = setTimeout(() => initWebSocket(), 5000)
    }

    ws.onerror = () => {
      ws?.close()
    }
  }

  function handleNewMessage(newMessage: any) {
    scheduleFetchUnreadCount()
    listeners.forEach(cb => cb(newMessage))
  }

  function setCurrentChat(id: number | null) {
    currentOpenChatId.value = id
  }

  function cleanupTimers() {
    if (heartbeatTimer) {
      clearInterval(heartbeatTimer)
      heartbeatTimer = null
    }
    if (unreadFetchTimer) {
      clearTimeout(unreadFetchTimer)
      unreadFetchTimer = null
    }
  }

  function disconnect() {
    if (reconnectTimer) {
      clearTimeout(reconnectTimer)
      reconnectTimer = null
    }
    cleanupTimers()
    if (ws) {
      ws.onclose = null
      ws.close()
      ws = null
    }
    wsConnected.value = false
  }

  return {
    currentOpenChatId,
    wsConnected,
    totalUnread,
    fetchUnreadCount,
    initWebSocket,
    setCurrentChat,
    disconnect,
  }
})
