• Provides rate limit context to its children, managing rate limit state and notifications.

    Parameters

    • children: { children: ReactNode }

      The React children to be wrapped by the provider.

    Returns Element

    The rate limit context provider with value for consumers.

    export function RateLimitProvider({ children }: { children: ReactNode }) {
    const [rateLimitState, setRateLimitState] = useState<RateLimitState>({
    isRateLimited: false,
    retryAfter: null,
    message: null,
    });

    // Use string type only for toast ID to fix TypeScript error
    const [toastId, setToastId] = useState<string | null>(null);

    // Function to set rate limit state
    const setRateLimit = (
    isLimited: boolean,
    retryTime?: number,
    message?: string,
    ) => {
    const retryTimestamp = retryTime ? Date.now() + retryTime * 1000 : null;

    console.log("Setting rate limit state:", {
    isLimited,
    retryTimestamp,
    message,
    });

    setRateLimitState({
    isRateLimited: isLimited,
    retryAfter: retryTimestamp,
    message:
    message ||
    "AniList API rate limit reached. Please wait before making more requests.",
    });
    };

    // Function to clear rate limit state
    const clearRateLimit = () => {
    setRateLimitState({
    isRateLimited: false,
    retryAfter: null,
    message: null,
    });
    };

    // Periodically check rate limit status from main process
    useEffect(() => {
    // Skip if we're in a browser environment without Electron
    if (!window.electronAPI?.anilist?.getRateLimitStatus) return;

    const checkRateLimitStatus = async () => {
    try {
    const status = await window.electronAPI.anilist.getRateLimitStatus();

    if (status.isRateLimited) {
    setRateLimitState({
    isRateLimited: true,
    retryAfter: status.retryAfter,
    message:
    "AniList API rate limit reached. Please wait before making more requests.",
    });
    } else if (rateLimitState.isRateLimited) {
    // Clear rate limit if it was previously set but is now cleared
    clearRateLimit();
    }
    } catch (error) {
    console.error("Error checking rate limit status:", error);
    }
    };

    // Check immediately on component mount
    checkRateLimitStatus();

    // Then check periodically
    const interval = setInterval(checkRateLimitStatus, 1000);

    return () => clearInterval(interval);
    }, [rateLimitState.isRateLimited]);

    // Listen for global rate limiting events
    useEffect(() => {
    const handleRateLimit = (event: Event) => {
    const customEvent = event as CustomEvent;
    if (customEvent.detail) {
    const { retryAfter, message } = customEvent.detail;
    console.log("Received rate limit event:", customEvent.detail);
    setRateLimit(true, retryAfter, message);
    }
    };

    // Add event listener for the custom rate limiting event
    window.addEventListener("anilist:rate-limited", handleRateLimit);

    // Clean up the listener on unmount
    return () => {
    window.removeEventListener("anilist:rate-limited", handleRateLimit);
    };
    }, []);

    // Effect to show/hide toast notification based on rate limit state
    useEffect(() => {
    if (rateLimitState.isRateLimited && rateLimitState.retryAfter) {
    // Create a dismissible persistent toast
    const id = toast.warning(
    <RateLimitToast
    message={rateLimitState.message || "Rate limited by AniList API"}
    retryAfter={rateLimitState.retryAfter}
    onComplete={clearRateLimit}
    />,
    {
    id: "rate-limit-toast",
    duration: Infinity, // Don't auto-dismiss
    },
    );

    // Force cast to string to fix TypeScript error
    setToastId(id as unknown as string);
    } else if (toastId) {
    // Dismiss the toast when no longer rate limited
    toast.dismiss(toastId);
    setToastId(null);
    }
    }, [rateLimitState.isRateLimited, rateLimitState.retryAfter]);

    return (
    <RateLimitContext.Provider
    value={{ rateLimitState, setRateLimit, clearRateLimit }}
    >
    {children}
    </RateLimitContext.Provider>
    );
    }