'use client';

import { useEffect, useRef, useCallback } from 'react';
import { io, type Socket } from 'socket.io-client';
import { toast } from 'sonner';
import { useAuthStore } from '@/lib/auth-store';
import type { NotificationDto } from '@/lib/notifications-api';
import { useNotificationsStore } from '@/lib/notifications-store';

/** Base URL for the Socket.IO server (without namespace). */
const SOCKET_URL =
  process.env['NEXT_PUBLIC_API_URL']?.replace('/api/v1', '') ||
  'http://localhost:3001';

/**
 * Hook that manages the Socket.IO connection for real-time notifications.
 *
 * Connects to the `/notifications` namespace on the backend
 * {@link NotificationsGateway} with JWT auth handshake.
 *
 * - Authenticates via `auth.token` (access-token from cookie or store)
 * - Listens for `notification:new` → adds to store + shows toast
 * - Listens for `notification:unread-count` → syncs badge count
 * - Auto-reconnects with exponential backoff (1 s → 10 s)
 * - Disconnects on logout
 */
export function useSocketNotifications() {
  const socketRef = useRef<Socket | null>(null);
  const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
  const { addNotification, incrementUnread, setUnreadCount } =
    useNotificationsStore();

  /** Extract the access-token cookie value (if present). */
  const getAccessToken = useCallback((): string | undefined => {
    if (typeof document === 'undefined') return undefined;
    const match = document.cookie
      .split('; ')
      .find((c) => c.startsWith('goodgo_access_token='));
    return match?.split('=')[1];
  }, []);

  useEffect(() => {
    if (!isAuthenticated) {
      if (socketRef.current) {
        socketRef.current.disconnect();
        socketRef.current = null;
      }
      return;
    }

    // Don't create duplicate connections
    if (socketRef.current?.connected) return;

    const token = getAccessToken();

    const socket = io(`${SOCKET_URL}/notifications`, {
      path: '/socket.io',
      auth: token ? { token } : undefined,
      withCredentials: true, // Also send httpOnly cookies as fallback
      transports: ['websocket', 'polling'],
      reconnection: true,
      reconnectionAttempts: Infinity,
      reconnectionDelay: 1000,
      reconnectionDelayMax: 10000,
      autoConnect: true,
    });

    socket.on('connect', () => {
      // Connection established — unread count arrives via notification:unread-count
    });

    socket.on('notification:new', (data: NotificationDto) => {
      addNotification(data);
      incrementUnread();

      // Show a sonner toast for the incoming notification
      toast(data.title ?? 'Thông báo mới', {
        description: data.body,
        duration: 5000,
      });
    });

    socket.on(
      'notification:unread-count',
      (data: { unreadCount: number }) => {
        setUnreadCount(data.unreadCount);
      },
    );

    socket.on('disconnect', (reason) => {
      // Socket.IO auto-reconnects for transport errors.
      // Only server-initiated disconnects need explicit reconnect.
      if (reason === 'io server disconnect') {
        socket.connect();
      }
    });

    socket.on('connect_error', (err) => {
      console.warn('[ws] connection error:', err.message);
    });

    socketRef.current = socket;

    return () => {
      socket.disconnect();
      socketRef.current = null;
    };
  }, [isAuthenticated, addNotification, incrementUnread, setUnreadCount, getAccessToken]);
}
