import { useRef, useCallback, useEffect, useState } from "react";
import { trpc } from "@/lib/trpc";
import { toast } from "sonner";

interface UsePhaseAutoSaveOptions {
  debounceMs?: number;
  onSaved?: () => void;
  onError?: (error: Error) => void;
}

export function usePhaseAutoSave({ debounceMs = 1000, onSaved, onError }: UsePhaseAutoSaveOptions = {}) {
  const [lastError, setLastError] = useState<Error | null>(null);
  const [retryCount, setRetryCount] = useState(0);
  const utils = trpc.useUtils();

  const updateMutation = trpc.updatePhase.useMutation({
    onMutate: async (variables) => {
      // Cancel any outgoing refetches
      await utils.getPhase.cancel({ id: variables.id });
      await utils.listPhases.cancel();

      // Snapshot previous values
      const previousPhase = utils.getPhase.getData({ id: variables.id });
      const previousPhases = utils.listPhases.getData();

      // Optimistically update phase in cache
      if (previousPhase) {
        const optimisticUpdate = {
          ...previousPhase,
          ...(variables.content !== undefined && { content: variables.content }),
          updatedAt: new Date().toISOString(),
        };

        utils.getPhase.setData({ id: variables.id }, optimisticUpdate);

        // Also update in the phases list if present
        if (previousPhases) {
          utils.listPhases.setData(undefined,
            previousPhases.map(phase =>
              phase.id === variables.id ? optimisticUpdate : phase
            )
          );
        }
      }

      return { previousPhase, previousPhases };
    },
    onSuccess: () => {
      setLastError(null);
      setRetryCount(0);
      onSaved?.();
    },
    onError: (error, variables, context) => {
      // Revert optimistic updates
      if (context?.previousPhase) {
        utils.getPhase.setData({ id: variables.id }, context.previousPhase);
      }
      if (context?.previousPhases) {
        utils.listPhases.setData(undefined, context.previousPhases);
      }
      setLastError(error);
      onError?.(error);
    },
    // Invalidation handled globally by MutationCache
  });
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const pendingRef = useRef<{
    id: string;
    content?: string | null;
  } | null>(null);

  const flush = useCallback(async () => {
    if (timerRef.current) {
      clearTimeout(timerRef.current);
      timerRef.current = null;
    }
    if (pendingRef.current) {
      const data = pendingRef.current;
      pendingRef.current = null;

      try {
        await updateMutation.mutateAsync(data);
        return;
      } catch (error) {
        // Retry logic for transient failures
        if (retryCount < 2 && error instanceof Error) {
          setRetryCount(prev => prev + 1);
          pendingRef.current = data; // Restore data for retry

          // Exponential backoff: 1s, 2s
          const delay = 1000 * Math.pow(2, retryCount);
          setTimeout(() => void flush(), delay);
          return;
        }

        // Final failure - show user feedback
        toast.error(`Failed to save phase: ${error instanceof Error ? error.message : 'Unknown error'}`, {
          action: {
            label: 'Retry',
            onClick: () => {
              setRetryCount(0);
              pendingRef.current = data;
              void flush();
            },
          },
        });
        throw error;
      }
    }
    return Promise.resolve();
  }, [updateMutation, retryCount]);

  const save = useCallback(
    (id: string, data: { content?: string | null }) => {
      pendingRef.current = { id, ...data };

      if (timerRef.current) {
        clearTimeout(timerRef.current);
      }

      timerRef.current = setTimeout(() => void flush(), debounceMs);
    },
    [debounceMs, flush],
  );

  // Flush on unmount
  useEffect(() => {
    return () => {
      if (timerRef.current) {
        clearTimeout(timerRef.current);
      }
      if (pendingRef.current) {
        const data = pendingRef.current;
        pendingRef.current = null;
        updateMutation.mutate(data);
      }
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return {
    save,
    flush,
    isSaving: updateMutation.isPending,
    lastError,
    hasError: lastError !== null,
    retryCount,
  };
}
