// src/hooks/useNotificationSocket.tsx
import React, {
  createContext,
  useContext,
  useEffect,
  useRef,
  useState,
} from "react";
import { io, Socket } from "socket.io-client";
import { toast } from "sonner";
import { getEnvUrl } from "@/shared/config/env";
import { useReminder } from "@/shared/hooks/useReminder";

// Define notification data structure
export interface INotification {
  id?: string;
  message: string;
  timestamp?: string;
  createdAt?: string;
  updatedAt?: string;
  isSeen?: boolean;
  itemId?: string;
  subject?: { en?: string; am?: string } | string;
  metadata?: { route?: string; recordType?: string };
  type?: "info" | "warning" | "error";
}

// Define context value type
interface NotificationContextValue {
  socket: Socket | null;
  notifications: INotification[];
  scheduleReminder: (notification: INotification, minutes: number) => void;
}

// Create the Notification context
const NotificationContext = createContext<NotificationContextValue>({
  socket: null,
  notifications: [],
  scheduleReminder: () => {},
});

// Define props for the provider
interface NotificationProviderProps {
  userId: string;
  children: React.ReactNode;
}

// Notification provider component
export const NotificationProvider: React.FC<NotificationProviderProps> = ({
  userId,
  children,
}) => {
  const notificationUrl = getEnvUrl("VITE_NOTIFICATION_URL");
  const socketRef = useRef<Socket | null>(null);
  const [notifications, setNotifications] = useState<INotification[]>([]);
  const { scheduleReminder: scheduleReminderHook } = useReminder();

  // Request browser notification permission once
  useEffect(() => {
    if ("Notification" in window && Notification.permission !== "granted") {
      Notification.requestPermission().then((permission) => {
        if (permission !== "granted") {
          console.warn("Browser notifications are disabled by the user.");
        }
      });
    }
  }, []);

  // Function to schedule a reminder from a notification
  const scheduleReminder = (notification: INotification, minutes: number) => {
    const remindAt = new Date(Date.now() + minutes * 60 * 1000).toISOString();
    
    const subject = typeof notification.subject === "object" 
      ? notification.subject 
      : { en: String(notification.subject || "Notification") };

    scheduleReminderHook({
      id: `reminder-${notification.id || Date.now()}`,
      notificationId: notification.id || `notif-${Date.now()}`,
      message: notification.message,
      subject: { 
        en: subject.en || "Notification",
        am: subject.am 
      },
      remindAt,
      itemId: notification.itemId || "",
      metadata: notification.metadata,
    });

    toast.success(`Reminder set for ${minutes} minutes from now`);
  };

  // Connect socket when userId changes
  useEffect(() => {
    if (!userId) return;

    // Disconnect any existing socket before creating a new one to prevent leaks
    if (socketRef.current) {
      socketRef.current.disconnect();
      socketRef.current = null;
    }

    const socket = io(notificationUrl, {
      transports: ["websocket"],
      query: { id: userId, type: "user" },
      reconnection: true,
      reconnectionAttempts: 15,
      reconnectionDelay: 1000,
      reconnectionDelayMax: 30000,
    });

    socketRef.current = socket;

    // Listen for notifications
    socket.on("my-notification", (data: INotification) => {
      if (!data?.message) return;

      const normalized: INotification = {
        ...data,
        id: data.id || `rt-${Date.now()}`,
        createdAt: data.createdAt || new Date().toISOString(),
        updatedAt: data.updatedAt || data.createdAt || new Date().toISOString(),
        isSeen: data.isSeen ?? false,
        itemId: data.itemId || data.id || "",
      };

      // Show toast popup
      toast(normalized.message, {
        description: new Date().toLocaleTimeString(),
        duration: 4000,
      });

      // Add to notification list
      setNotifications((prev) => {
        const deduped = prev.filter((item) => item.id !== normalized.id);
        return [normalized, ...deduped];
      });

      // Broadcast to the shared notification hook for site-level sync
      window.dispatchEvent(
        new CustomEvent("record-management:notification-received", {
          detail: normalized,
        })
      );

      // Show browser notification if permission is granted
      if ("Notification" in window && Notification.permission === "granted") {
        new Notification("New Notification", { body: normalized.message });
      }
    });

    return () => {
      socket.disconnect();
      socketRef.current = null;
    };
  }, [notificationUrl, userId]);

  return (
    <NotificationContext.Provider
      value={{ socket: socketRef.current, notifications, scheduleReminder }}>
      {children}
    </NotificationContext.Provider>
  );
};

// Custom hook to use the notification context
export const useSocketNotification = () => useContext(NotificationContext);
