import { useMutation, useQueryClient, QueryKey } from '@tanstack/react-query';
import { signalRService } from '../services/signalr';

interface OptimisticMutationOptions<TData, TVariables> {
  mutationFn: (variables: TVariables) => Promise<TData>;
  entityType: string;
  queryKey: QueryKey;
  // Funzione per aggiornare ottimisticamente la cache
  optimisticUpdate?: (oldData: any, variables: TVariables) => any;
  // Azione SignalR da notificare
  action?: 'created' | 'updated' | 'deleted';
  onSuccess?: (data: TData, variables: TVariables) => void;
  onError?: (error: Error, variables: TVariables) => void;
}

/**
 * Hook per mutation ottimistiche con notifiche SignalR
 * Le modifiche appaiono immediatamente e vengono sincronizzate in background
 */
export function useOptimisticMutation<TData = any, TVariables = any>({
  mutationFn,
  entityType,
  queryKey,
  optimisticUpdate,
  action = 'updated',
  onSuccess,
  onError,
}: OptimisticMutationOptions<TData, TVariables>) {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn,

    // Prima della mutation: applica l'update ottimistico
    onMutate: async (variables) => {
      // Cancella query in corso per evitare conflitti
      await queryClient.cancelQueries({ queryKey });

      // Salva lo stato precedente per rollback
      const previousData = queryClient.getQueryData(queryKey);

      // Applica update ottimistico se fornito
      if (optimisticUpdate && previousData) {
        queryClient.setQueryData(queryKey, (old: any) => optimisticUpdate(old, variables));
      }

      return { previousData };
    },

    // In caso di errore: rollback allo stato precedente
    onError: (error, variables, context) => {
      if (context?.previousData) {
        queryClient.setQueryData(queryKey, context.previousData);
      }
      onError?.(error as Error, variables);
    },

    // Dopo il successo: notifica SignalR e invalida la query
    onSuccess: async (data, variables) => {
      // Notifica altri client via SignalR
      await signalRService.notifyChange(entityType, action, data);
      onSuccess?.(data, variables);
    },

    // Sempre dopo la mutation: sincronizza con il server
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey });
    },
  });
}

/**
 * Hook semplificato per mutation che non richiedono update ottimistico
 * ma notificano comunque SignalR
 */
export function useNotifyingMutation<TData = any, TVariables = any>({
  mutationFn,
  entityType,
  action = 'updated',
  invalidateKeys = [],
  onSuccess,
}: {
  mutationFn: (variables: TVariables) => Promise<TData>;
  entityType: string;
  action?: 'created' | 'updated' | 'deleted' | 'bulk';
  invalidateKeys?: QueryKey[];
  onSuccess?: (data: TData, variables: TVariables) => void;
}) {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn,
    onSuccess: async (data, variables) => {
      // Notifica altri client
      await signalRService.notifyChange(entityType, action, data);

      // Invalida le query specificate
      for (const key of invalidateKeys) {
        queryClient.invalidateQueries({ queryKey: key });
      }

      onSuccess?.(data, variables);
    },
  });
}
