import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import type { RouteLocationNormalizedLoaded } from 'vue-router'

import { fetchUnreadNotificationCount } from '@/features/auth/api/notifications'
import { useSessionStore } from '@/stores/session'

export const notificationUnreadChangedEvent = 'notification-unread-changed'

export function useNotificationUnreadCount(route: RouteLocationNormalizedLoaded) {
  const session = useSessionStore()
  const unreadCount = ref(0)
  let timer: number | null = null
  let requestID = 0

  const unreadLabel = computed(() => (unreadCount.value > 99 ? '99+' : String(unreadCount.value)))

  function stopPolling() {
    if (timer) {
      window.clearInterval(timer)
      timer = null
    }
  }

  async function loadUnreadCount() {
    if (!session.isLoggedIn) {
      unreadCount.value = 0
      return
    }

    const currentID = ++requestID
    try {
      const count = await fetchUnreadNotificationCount()
      if (currentID === requestID) {
        unreadCount.value = count
      }
    } catch {
      // 角标静默失败，避免影响主流程。
    }
  }

  function startPolling() {
    stopPolling()
    void loadUnreadCount()
    timer = window.setInterval(loadUnreadCount, 30_000)
  }

  function resumePollingIfVisible() {
    if (document.hidden || !session.isLoggedIn) return
    startPolling()
  }

  function handleVisibilityChange() {
    if (document.hidden) {
      stopPolling()
      return
    }
    resumePollingIfVisible()
  }

  function handleUnreadChanged() {
    void loadUnreadCount()
  }

  onMounted(() => {
    window.addEventListener(notificationUnreadChangedEvent, handleUnreadChanged)
    document.addEventListener('visibilitychange', handleVisibilityChange)
    resumePollingIfVisible()
  })

  onBeforeUnmount(() => {
    stopPolling()
    window.removeEventListener(notificationUnreadChangedEvent, handleUnreadChanged)
    document.removeEventListener('visibilitychange', handleVisibilityChange)
  })

  watch(
    () => session.isLoggedIn,
    loggedIn => {
      if (loggedIn) {
        resumePollingIfVisible()
        return
      }
      stopPolling()
      unreadCount.value = 0
    }
  )

  watch(
    () => route.fullPath,
    () => {
      void loadUnreadCount()
    }
  )

  return {
    unreadCount,
    unreadLabel,
    refreshUnreadCount: loadUnreadCount,
  }
}
