/**
 * Hook optimisé pour les requêtes React Query avec cache intelligent
 */

import { useQuery, UseQueryOptions, QueryKey } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react';

interface OptimizedQueryOptions<T> extends Omit<UseQueryOptions<T>, 'queryKey' | 'queryFn'> {
  queryKey: QueryKey;
  queryFn?: () => Promise<T>;
  cacheStrategy?: 'realtime' | 'frequent' | 'static' | 'custom';
  customCacheTime?: number;
  customStaleTime?: number;
}

/**
 * Stratégies de cache prédéfinies selon le type de données
 */
const CACHE_STRATEGIES = {
  // Données temps réel (commandes actives, tracking)
  realtime: {
    staleTime: 10 * 1000, // 10 secondes
    gcTime: 60 * 1000,    // 1 minute
    refetchInterval: 30 * 1000, // 30 secondes
  },
  
  // Données fréquemment mises à jour (notifications, stock)
  frequent: {
    staleTime: 2 * 60 * 1000,  // 2 minutes
    gcTime: 10 * 60 * 1000,    // 10 minutes
    refetchOnWindowFocus: true,
  },
  
  // Données statiques (médicaments, utilisateurs)
  static: {
    staleTime: 15 * 60 * 1000, // 15 minutes
    gcTime: 60 * 60 * 1000,    // 1 heure
    refetchOnWindowFocus: false,
  },
  
  // Configuration personnalisée
  custom: {}
} as const;

/**
 * Hook optimisé avec stratégies de cache intelligentes
 */
export function useOptimizedQuery<T>({
  queryKey,
  queryFn,
  cacheStrategy = 'frequent',
  customCacheTime,
  customStaleTime,
  ...options
}: OptimizedQueryOptions<T>) {
  
  // Sélectionner la stratégie de cache
  const cacheConfig = useMemo(() => {
    const strategy = CACHE_STRATEGIES[cacheStrategy];
    
    return {
      ...strategy,
      ...(customStaleTime && { staleTime: customStaleTime }),
      ...(customCacheTime && { gcTime: customCacheTime }),
    };
  }, [cacheStrategy, customStaleTime, customCacheTime]);
  
  // Optimiser la fonction de requête
  const optimizedQueryFn = useCallback(async (): Promise<T> => {
    if (!queryFn) throw new Error('QueryFn is required');
    
    const start = Date.now();
    
    try {
      const result = await queryFn();
      const duration = Date.now() - start;
      
      // Log des requêtes lentes
      if (duration > 2000) {
        console.warn(`[SLOW API CALL] ${JSON.stringify(queryKey)}: ${duration}ms`);
      }
      
      return result;
    } catch (error) {
      const duration = Date.now() - start;
      console.error(`[API ERROR] ${JSON.stringify(queryKey)}: ${duration}ms`, error);
      throw error;
    }
  }, [queryFn, queryKey]);
  
  return useQuery<T>({
    queryKey,
    queryFn: optimizedQueryFn,
    ...cacheConfig,
    ...options,
  });
}

/**
 * Hook spécialisé pour les listes paginées
 */
export interface PaginationParams {
  page: number;
  limit: number;
  sortBy?: string;
  sortOrder?: 'asc' | 'desc';
}

export interface PaginatedData<T> {
  data: T[];
  pagination: {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
    hasNext: boolean;
    hasPrev: boolean;
  };
}

export function usePaginatedQuery<T>(
  baseQueryKey: QueryKey,
  queryFn: (params: PaginationParams) => Promise<PaginatedData<T>>,
  paginationParams: PaginationParams,
  options?: Omit<OptimizedQueryOptions<PaginatedData<T>>, 'queryKey' | 'queryFn'>
) {
  const queryKey = useMemo(() => 
    [...baseQueryKey, 'paginated', paginationParams], 
    [baseQueryKey, paginationParams]
  );
  
  const optimizedQueryFn = useCallback(
    () => queryFn(paginationParams),
    [queryFn, paginationParams]
  );
  
  return useOptimizedQuery<PaginatedData<T>>({
    queryKey,
    queryFn: optimizedQueryFn,
    cacheStrategy: 'frequent',
    placeholderData: (previousData) => previousData, // Garde les données précédentes pendant le chargement
    ...options,
  });
}

/**
 * Hook pour les requêtes en temps réel avec WebSocket fallback
 */
export function useRealtimeQuery<T>(
  queryKey: QueryKey,
  queryFn: () => Promise<T>,
  websocketTopic?: string,
  options?: Omit<OptimizedQueryOptions<T>, 'queryKey' | 'queryFn' | 'cacheStrategy'>
) {
  return useOptimizedQuery<T>({
    queryKey,
    queryFn,
    cacheStrategy: 'realtime',
    refetchInterval: websocketTopic ? false : 10000, // Pas de polling si WebSocket
    refetchOnWindowFocus: true,
    refetchOnReconnect: true,
    ...options,
  });
}

/**
 * Hook pour les données de cache long (configuration, utilisateurs)
 */
export function useStaticQuery<T>(
  queryKey: QueryKey,
  queryFn: () => Promise<T>,
  options?: Omit<OptimizedQueryOptions<T>, 'queryKey' | 'queryFn' | 'cacheStrategy'>
) {
  return useOptimizedQuery<T>({
    queryKey,
    queryFn,
    cacheStrategy: 'static',
    retry: 2,
    ...options,
  });
}

/**
 * Utilitaires pour la gestion du cache
 */
export const QueryUtils = {
  /**
   * Génère une clé de cache unique basée sur les paramètres
   */
  generateCacheKey: (base: string, params: Record<string, any>): QueryKey => {
    const sortedParams = Object.keys(params)
      .sort()
      .reduce((acc, key) => {
        acc[key] = params[key];
        return acc;
      }, {} as Record<string, any>);
    
    return [base, sortedParams];
  },
  
  /**
   * Invalide les caches liés à un pattern
   */
  invalidatePattern: (queryClient: any, pattern: string) => {
    queryClient.invalidateQueries({
      predicate: (query: any) => 
        query.queryKey.some((key: any) => 
          typeof key === 'string' && key.includes(pattern)
        )
    });
  },
  
  /**
   * Nettoie les anciens caches
   */
  cleanupOldCaches: (queryClient: any, olderThan: number = 24 * 60 * 60 * 1000) => {
    const now = Date.now();
    queryClient.getQueryCache().findAll().forEach((query: any) => {
      if (now - query.state.dataUpdatedAt > olderThan) {
        queryClient.removeQueries({ queryKey: query.queryKey });
      }
    });
  }
};