"use client"

import { useEffect, useRef, useCallback, useSyncExternalStore } from "react"

import type { Notification } from "../types"

interface UseDesktopNotificationsOptions {
  /** 是否启用桌面推送（默认 false） */
  enabled?: boolean
  /** 通知点击时的跳转回调 */
  onClick?: (notification: Notification) => void
}

interface UseDesktopNotificationsResult {
  /** 当前权限状态 */
  permission: NotificationPermission | "unsupported"
  /** 是否已授权 */
  isGranted: boolean
  /** 请求权限 */
  requestPermission: () => Promise<void>
  /** 发送桌面通知 */
  showNotification: (notification: Notification) => void
}

// v3: 使用 useSyncExternalStore 订阅浏览器 Notification 权限。
// 模块级监听器集合：requestPermission 完成后手动通知 React 重新读取快照。
// Notification API 没有标准的 permissionchange 事件，需手动触发。
const permissionListeners = new Set<() => void>()

function subscribePermission(onStoreChange: () => void): () => void {
  permissionListeners.add(onStoreChange)
  return () => {
    permissionListeners.delete(onStoreChange)
  }
}

function getPermissionSnapshot(): NotificationPermission | "unsupported" {
  if (typeof window === "undefined" || !("Notification" in window)) return "unsupported"
  return Notification.permission
}

function getPermissionServerSnapshot(): NotificationPermission | "unsupported" {
  // SSR 期间返回固定值，与 client hydration 一致，避免 hydration mismatch。
  // hydration 完成后 React 自动切换到 getSnapshot 并触发重新渲染。
  return "unsupported"
}

function notifyPermissionChange(): void {
  permissionListeners.forEach((listener) => listener())
}

/**
 * 桌面通知 Hook
 *
 * 使用浏览器 Notification API 发送桌面推送通知，
 * 当用户不在页面标签页时仍可收到通知提醒。
 *
 * 使用场景：
 * - SSE 收到新通知时触发桌面推送
 * - 用户切换到其他标签页时仍能收到提醒
 *
 * 权限流程：
 * 1. 默认权限为 "default"（未询问）
 * 2. 调用 requestPermission() 弹出浏览器权限询问框
 * 3. 用户授权后可调用 showNotification 发送桌面通知
 *
 * 浏览器兼容性：
 * - Chrome/Edge/Firefox 桌面版完整支持
 * - Safari 桌面版 13+ 支持
 * - 移动端浏览器不支持（自动降级为无桌面推送）
 *
 * v3: 使用 useSyncExternalStore 替代 useState + useEffect 检测权限，
 * 避免 SSR/CSR 不一致导致的 hydration mismatch，同时满足
 * react-hooks/set-state-in-effect 规则。
 */
export function useDesktopNotifications(
  options?: UseDesktopNotificationsOptions
): UseDesktopNotificationsResult {
  const enabled = options?.enabled ?? false

  // v3: useSyncExternalStore 自动处理 SSR/CSR 一致性
  // - SSR: getPermissionServerSnapshot → "unsupported"
  // - hydration: 仍使用 server snapshot（一致，无 mismatch）
  // - hydration 后: 切换到 getPermissionSnapshot，如有差异自动 re-render
  const permission = useSyncExternalStore(
    subscribePermission,
    getPermissionSnapshot,
    getPermissionServerSnapshot
  )

  const onClickRef = useRef(options?.onClick)
  useEffect(() => {
    onClickRef.current = options?.onClick
  }, [options?.onClick])

  const isGranted = permission === "granted"

  const requestPermission = useCallback(async (): Promise<void> => {
    if (typeof window === "undefined" || !("Notification" in window)) return

    try {
      await Notification.requestPermission()
      // 通知 React 重新读取快照（Notification.permission 可能已改变）
      notifyPermissionChange()
    } catch {
      // 某些浏览器可能抛出异常，静默处理
    }
  }, [])

  const showNotification = useCallback(
    (notification: Notification): void => {
      if (!enabled || !isGranted) return
      if (typeof window === "undefined" || !("Notification" in window)) return

      try {
        const desktopNotif = new Notification(notification.title, {
          body: notification.content ?? "",
          tag: notification.id, // 避免重复通知
          ...(notification.link ? { data: notification.link } : {}),
        })

        desktopNotif.onclick = () => {
          window.focus()
          onClickRef.current?.(notification)
          desktopNotif.close()
        }
      } catch {
        // 通知创建失败静默处理
      }
    },
    [enabled, isGranted]
  )

  // 当 enabled 变为 true 且权限为 default 时，自动请求权限
  useEffect(() => {
    if (!enabled || permission !== "default") return
    if (typeof window === "undefined" || !("Notification" in window)) return

    let cancelled = false
    Notification.requestPermission()
      .then(() => {
        if (!cancelled) notifyPermissionChange()
      })
      .catch(() => {
        // 某些浏览器可能抛出异常，静默处理
      })

    return () => {
      cancelled = true
    }
  }, [enabled, permission])

  return {
    permission,
    isGranted,
    requestPermission,
    showNotification,
  }
}
