import React, {
  createContext,
  useContext,
  useState,
  useEffect,
  useCallback,
  useRef,
} from "react";
import { useAuth } from "@clerk/clerk-expo";
import {
  fetchNotifications,
  fetchUnreadCount,
  markAsRead,
  markAllAsRead,
  deleteNotification,
  type Notification,
} from "../api/notifications";
import log from "../utils/logger";

interface NotificationsContextType {
  notifications: Notification[];
  unreadCount: number;
  loading: boolean;
  refetchNotifications: () => Promise<void>;
  markNotificationAsRead: (id: string) => Promise<void>;
  markAllAsReadAction: () => Promise<void>;
  deleteNotificationAction: (id: string) => Promise<void>;
}

const NotificationsContext = createContext<
  NotificationsContextType | undefined
>(undefined);

export function NotificationsProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const { getToken, isSignedIn } = useAuth();
  const [notifications, setNotifications] = useState<Notification[]>([]);
  const [unreadCount, setUnreadCount] = useState(0);
  const [loading, setLoading] = useState(false);
  const fetchInProgressRef = useRef(false);
  const lastFetchTimeRef = useRef(0);

  const refetchNotifications = useCallback(async () => {
    if (!isSignedIn) return;

    const now = Date.now();
    const timeSinceLastFetch = now - lastFetchTimeRef.current;

    // Prevent duplicate concurrent fetches
    if (fetchInProgressRef.current) {
      log.debug("Skipping duplicate notification fetch (already in progress)");
      return;
    }

    // Debounce: prevent fetches within 1 second of the last fetch
    if (timeSinceLastFetch < 1000) {
      log.debug("Skipping duplicate notification fetch (debounced)", {
        timeSinceLastFetch: `${timeSinceLastFetch}ms`,
      });
      return;
    }

    try {
      fetchInProgressRef.current = true;
      lastFetchTimeRef.current = now;
      setLoading(true);
      const token = await getToken();

      // Fetch notifications and unread count in parallel
      const [notificationsData, count] = await Promise.all([
        fetchNotifications(token),
        fetchUnreadCount(token),
      ]);

      setNotifications(notificationsData);
      setUnreadCount(count);

      log.debug("Notifications fetched", {
        total: notificationsData.length,
        unread: count,
      });
    } catch (error) {
      log.error("Failed to fetch notifications", error);
    } finally {
      setLoading(false);
      fetchInProgressRef.current = false;
    }
  }, [getToken, isSignedIn]);

  const markNotificationAsRead = useCallback(
    async (id: string) => {
      try {
        const token = await getToken();
        await markAsRead(id, token);

        // Update local state
        setNotifications((prev) =>
          prev.map((n) => (n.id === id ? { ...n, read: true } : n)),
        );

        setUnreadCount((prev) => Math.max(0, prev - 1));

        log.debug("Notification marked as read", { id });
      } catch (error) {
        log.error("Failed to mark notification as read", error);
        throw error;
      }
    },
    [getToken],
  );

  const markAllAsReadAction = useCallback(async () => {
    try {
      const token = await getToken();
      await markAllAsRead(token);

      // Update local state
      setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));
      setUnreadCount(0);

      log.debug("All notifications marked as read");
    } catch (error) {
      log.error("Failed to mark all notifications as read", error);
      throw error;
    }
  }, [getToken]);

  const deleteNotificationAction = useCallback(
    async (id: string) => {
      try {
        const token = await getToken();
        await deleteNotification(id, token);

        // Update local state
        const wasUnread =
          notifications.find((n) => n.id === id)?.read === false;
        setNotifications((prev) => prev.filter((n) => n.id !== id));

        if (wasUnread) {
          setUnreadCount((prev) => Math.max(0, prev - 1));
        }

        log.debug("Notification deleted", { id });
      } catch (error) {
        log.error("Failed to delete notification", error);
        throw error;
      }
    },
    [getToken, notifications],
  );

  // Initial fetch on mount
  useEffect(() => {
    if (isSignedIn) {
      refetchNotifications();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isSignedIn]); // Only run when sign-in state changes

  // Periodic refresh every 30 seconds
  useEffect(() => {
    if (!isSignedIn) return;

    const intervalId = setInterval(() => {
      refetchNotifications();
    }, 30000);

    return () => clearInterval(intervalId);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isSignedIn]); // Only run when sign-in state changes

  const value: NotificationsContextType = {
    notifications,
    unreadCount,
    loading,
    refetchNotifications,
    markNotificationAsRead,
    markAllAsReadAction,
    deleteNotificationAction,
  };

  return (
    <NotificationsContext.Provider value={value}>
      {children}
    </NotificationsContext.Provider>
  );
}

export function useNotifications() {
  const context = useContext(NotificationsContext);
  if (context === undefined) {
    throw new Error(
      "useNotifications must be used within a NotificationsProvider",
    );
  }
  return context;
}
