import { useRef, useCallback } from 'react';
import { supabase } from '@/integrations/supabase/client';
import { logger } from '@/lib/logger';
import { getErrorMessage } from '@/lib/errorHandler';
import { MODERATION_CONSTANTS } from '@/lib/moderation/constants';
import type { ModerationItem } from '@/types/moderation';

/**
 * Profile data structure returned from the database
 */
export interface CachedProfile {
  user_id: string;
  username: string;
  display_name?: string;
  avatar_url?: string;
}

/**
 * Hook for managing user profile caching
 * 
 * Uses ref-based storage to avoid triggering re-renders while providing
 * efficient caching for user profile lookups during moderation.
 * 
 * @example
 * ```tsx
 * const profileCache = useProfileCache();
 * 
 * // Get cached profile
 * const profile = profileCache.getCached(userId);
 * 
 * // Bulk fetch and cache profiles
 * const profiles = await profileCache.bulkFetch([id1, id2, id3]);
 * 
 * // Check if profile exists in cache
 * if (profileCache.has(userId)) {
 *   const profile = profileCache.getCached(userId);
 * }
 * 
 * // Clear cache
 * profileCache.clear();
 * ```
 */
export function useProfileCache() {
  // Use ref to prevent re-renders on cache updates
  const cacheRef = useRef<Map<string, CachedProfile>>(new Map());

  /**
   * Get a cached profile by user ID
   */
  const getCached = useCallback((userId: string): CachedProfile | undefined => {
    return cacheRef.current.get(userId);
  }, []);

  /**
   * Check if a profile is cached
   */
  const has = useCallback((userId: string): boolean => {
    return cacheRef.current.has(userId);
  }, []);

  /**
   * Set a cached profile with LRU eviction
   */
  const setCached = useCallback((userId: string, profile: CachedProfile): void => {
    const cache = cacheRef.current;
    
    // LRU eviction
    if (cache.size >= MODERATION_CONSTANTS.MAX_PROFILE_CACHE_SIZE) {
      const firstKey = cache.keys().next().value;
      if (firstKey) {
        cache.delete(firstKey);
        logger.log(`♻️ [ProfileCache] Evicted ${firstKey} (LRU)`);
      }
    }
    
    cache.set(userId, profile);
  }, []);

  /**
   * Get uncached user IDs from a list
   */
  const getUncachedIds = useCallback((userIds: string[]): string[] => {
    return userIds.filter(id => !cacheRef.current.has(id));
  }, []);

  /**
   * Bulk fetch user profiles from the database and cache them
   * Only fetches profiles that aren't already cached
   * 
   * @param userIds - Array of user IDs to fetch
   * @returns Array of fetched profiles
   */
  const bulkFetch = useCallback(async (userIds: string[]): Promise<CachedProfile[]> => {
    if (userIds.length === 0) return [];

    // Filter to only uncached IDs
    const uncachedIds = getUncachedIds(userIds);
    if (uncachedIds.length === 0) {
      // All profiles are cached, return them
      return userIds.map(id => getCached(id)).filter((p): p is CachedProfile => !!p);
    }

    try {
      const { data, error } = await supabase
        .from('profiles')
        .select('user_id, username, display_name, avatar_url')
        .in('user_id', uncachedIds);

      if (error) {
        logger.error('Error fetching profiles:', { error: getErrorMessage(error) });
        return [];
      }

      // Cache the fetched profiles
      if (data) {
        data.forEach((profile) => {
          const cachedProfile: CachedProfile = {
            ...profile,
            display_name: profile.display_name || undefined,
            avatar_url: profile.avatar_url || undefined
          };
          setCached(profile.user_id, cachedProfile);
        });
      }

      return (data || []).map(profile => ({
        ...profile,
        display_name: profile.display_name || undefined,
        avatar_url: profile.avatar_url || undefined
      }));
    } catch (error: unknown) {
      logger.error('Failed to bulk fetch profiles:', { error: getErrorMessage(error) });
      return [];
    }
  }, [getCached, setCached, getUncachedIds]);

  /**
   * Fetch and return profiles for a list of user IDs
   * Returns a Map for easy lookup
   * 
   * @param userIds - Array of user IDs to fetch
   * @returns Map of userId -> profile
   */
  const fetchAsMap = useCallback(async (userIds: string[]): Promise<Map<string, CachedProfile>> => {
    const profiles = await bulkFetch(userIds);
    return new Map(profiles.map(p => [p.user_id, p]));
  }, [bulkFetch]);

  /**
   * Fetch profiles for submitters and reviewers from submissions
   * Automatically extracts user IDs and reviewer IDs from submission data
   * 
   * @param submissions - Array of submissions with user_id and reviewer_id
   * @returns Map of userId -> profile for all users involved
   */
  const fetchForSubmissions = useCallback(async (submissions: ModerationItem[]): Promise<Map<string, CachedProfile>> => {
    const userIds = submissions.map(s => s.user_id).filter(Boolean);
    const reviewerIds = submissions.map(s => s.reviewer_id).filter((id): id is string => !!id);
    const allUserIds = [...new Set([...userIds, ...reviewerIds])];

    return await fetchAsMap(allUserIds);
  }, [fetchAsMap]);

  /**
   * Get a display name for a user (display_name or username)
   * Returns 'Unknown User' if not found in cache
   */
  const getDisplayName = useCallback((userId: string): string => {
    const profile = getCached(userId);
    if (!profile) return 'Unknown User';
    return profile.display_name || profile.username || 'Unknown User';
  }, [getCached]);

  /**
   * Invalidate (remove) a specific profile from cache
   */
  const invalidate = useCallback((userId: string): void => {
    cacheRef.current.delete(userId);
  }, []);

  /**
   * Clear all cached profiles
   */
  const clear = useCallback((): void => {
    cacheRef.current.clear();
  }, []);

  /**
   * Get cache size
   */
  const getSize = useCallback((): number => {
    return cacheRef.current.size;
  }, []);

  /**
   * Get all cached profile user IDs
   */
  const getAllCachedIds = useCallback((): string[] => {
    return Array.from(cacheRef.current.keys());
  }, []);

  /**
   * Get direct access to cache ref (for advanced use cases)
   * Use with caution - prefer using the provided methods
   */
  const getCacheRef = useCallback(() => cacheRef.current, []);

  // Return without useMemo wrapper (OPTIMIZED)
  return {
    getCached,
    has,
    setCached,
    getUncachedIds,
    bulkFetch,
    fetchAsMap,
    fetchForSubmissions,
    getDisplayName,
    invalidate,
    clear,
    getSize,
    getAllCachedIds,
    getCacheRef,
  };
}
