import { defineStore } from 'pinia'
import { ref, reactive, computed } from 'vue'
import { useAuthStore } from './auth'

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 unreadMap = reactive<Record<number, number>>({})
  const currentOpenChatId = ref<number | null>(null)
  const wsConnected = ref(false)

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

  const totalUnread = computed(() =>
    Object.values(unreadMap).reduce((sum, n) => sum + n, 0)
  )

  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
      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) {
    const authStore = useAuthStore()
    const myId = authStore.user?.id

    const isSystem = newMessage.type === 'NOTIFICATION' || newMessage.sender_id === null
    const convId = isSystem
      ? (newMessage.app_id ? -newMessage.app_id : 0)
      : (newMessage.sender_id === myId ? newMessage.receiver_id : newMessage.sender_id)

    if (convId !== currentOpenChatId.value && newMessage.sender_id !== myId) {
      unreadMap[convId] = (unreadMap[convId] || 0) + 1
    }

    listeners.forEach(cb => cb(newMessage))
  }

  function setCurrentChat(id: number | null) {
    currentOpenChatId.value = id
    if (id !== null) {
      unreadMap[id] = 0
    }
  }

  function clearChat(id: number) {
    unreadMap[id] = 0
  }

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

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

  return {
    unreadMap,
    currentOpenChatId,
    wsConnected,
    totalUnread,
    initWebSocket,
    setCurrentChat,
    clearChat,
    disconnect,
  }
})
