import React, { createContext, useContext, useState, useCallback, useMemo, useRef, ReactNode } from 'react'; import { DRIVE_FAVORITE_CHANGED_EVENT } from '@/services/drive'; interface CacheContextType { get: (key: string) => any; set: (key: string, value: any, ttl?: number) => void; invalidate: (key: string) => void; invalidatePattern: (pattern: string) => void; clear: () => void; } interface CacheEntry { value: any; expiry: number; } const CacheContext = createContext(undefined); export const CacheProvider: React.FC<{ children: ReactNode }> = ({ children }) => { const [cache, setCache] = useState>(new Map()); const cacheRef = useRef(cache); cacheRef.current = cache; const get = useCallback((key: string) => { const entry = cacheRef.current.get(key); if (!entry) return null; if (Date.now() > entry.expiry) { setCache(prev => { const newCache = new Map(prev); newCache.delete(key); return newCache; }); return null; } return entry.value; }, []); const set = useCallback((key: string, value: any, ttl: number = Infinity) => { setCache(prev => { const newCache = new Map(prev); newCache.set(key, { value, expiry: ttl === Infinity ? Infinity : Date.now() + ttl }); return newCache; }); }, []); const invalidate = useCallback((key: string) => { setCache(prev => { const newCache = new Map(prev); newCache.delete(key); return newCache; }); }, []); const invalidatePattern = useCallback((pattern: string) => { setCache(prev => { const newCache = new Map(prev); const regex = new RegExp(pattern.replace('*', '.*')); for (const key of newCache.keys()) { if (regex.test(key)) { newCache.delete(key); } } return newCache; }); }, []); const clear = useCallback(() => { setCache(new Map()); }, []); React.useEffect(() => { const handleLogout = () => { clear(); }; window.addEventListener('auth:logout', handleLogout); return () => window.removeEventListener('auth:logout', handleLogout); }, [clear]); React.useEffect(() => { const handleFavoriteChanged = () => { invalidatePattern('mydocs:*'); invalidate('favorites:starred'); invalidate('dashboard:main'); invalidate('recent:combined'); invalidate('shared:with_me'); }; window.addEventListener(DRIVE_FAVORITE_CHANGED_EVENT, handleFavoriteChanged); return () => window.removeEventListener(DRIVE_FAVORITE_CHANGED_EVENT, handleFavoriteChanged); }, [invalidate, invalidatePattern]); const value = useMemo(() => ({ get, set, invalidate, invalidatePattern, clear }), [get, set, invalidate, invalidatePattern, clear]); return ( {children} ); }; export const useCache = (): CacheContextType => { const context = useContext(CacheContext); if (!context) { throw new Error('useCache must be used within a CacheProvider'); } return context; };