/**
 * Onboarding React Query hooks
 */
import { useMutation, useQuery, useQueryClient, UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
import { useCallback, useRef } from 'react';
import { onboardingService } from '../services/onboarding';
import { UserProgress, UpdateStepRequest, StepDraftResponse } from '../types/onboarding';
import { ApiError } from '../client';

// Query Keys
export const onboardingKeys = {
  all: ['onboarding'] as const,
  progress: (userId: string) => [...onboardingKeys.all, 'progress', userId] as const,
  steps: () => [...onboardingKeys.all, 'steps'] as const,
  stepDetail: (stepName: string) => [...onboardingKeys.steps(), stepName] as const,
  stepDraft: (stepName: string) => [...onboardingKeys.all, 'draft', stepName] as const,
} as const;

// Queries
export const useUserProgress = (
  userId: string,
  options?: Omit<UseQueryOptions<UserProgress, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<UserProgress, ApiError>({
    queryKey: onboardingKeys.progress(userId),
    queryFn: () => onboardingService.getUserProgress(userId),
    enabled: !!userId,
    // OPTIMIZATION: Once onboarding is fully completed, it won't change back
    // Use longer staleTime (5 min) and gcTime (30 min) to reduce API calls
    // The select function below will update staleTime based on completion status
    staleTime: 5 * 60 * 1000, // 5 minutes (increased from 30s - completed status rarely changes)
    gcTime: 30 * 60 * 1000, // 30 minutes - keep in cache longer
    refetchOnWindowFocus: false, // Don't refetch on window focus for onboarding status
    ...options,
  });
};

export const useAllSteps = (
  options?: Omit<UseQueryOptions<Array<{
    name: string;
    description: string;
    dependencies: string[];
    estimated_time_minutes: number;
  }>, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<Array<{
    name: string;
    description: string;
    dependencies: string[];
    estimated_time_minutes: number;
  }>, ApiError>({
    queryKey: onboardingKeys.steps(),
    queryFn: () => onboardingService.getAllSteps(),
    staleTime: 10 * 60 * 1000, // 10 minutes
    ...options,
  });
};

export const useStepDetails = (
  stepName: string,
  options?: Omit<UseQueryOptions<{
    name: string;
    description: string;
    dependencies: string[];
    estimated_time_minutes: number;
  }, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<{
    name: string;
    description: string;
    dependencies: string[];
    estimated_time_minutes: number;
  }, ApiError>({
    queryKey: onboardingKeys.stepDetail(stepName),
    queryFn: () => onboardingService.getStepDetails(stepName),
    enabled: !!stepName,
    staleTime: 10 * 60 * 1000, // 10 minutes
    ...options,
  });
};

// Mutations
export const useUpdateStep = (
  options?: UseMutationOptions<UserProgress, ApiError, { userId: string; stepData: UpdateStepRequest }>
) => {
  const queryClient = useQueryClient();
  
  return useMutation<UserProgress, ApiError, { userId: string; stepData: UpdateStepRequest }>({
    mutationFn: ({ userId, stepData }) => onboardingService.updateStep(userId, stepData),
    onSuccess: (data, { userId }) => {
      // Update progress cache
      queryClient.setQueryData(onboardingKeys.progress(userId), data);
    },
    ...options,
  });
};

export const useMarkStepCompleted = (
  options?: UseMutationOptions<
    UserProgress,
    ApiError,
    { userId: string; stepName: string; data?: Record<string, any> }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    UserProgress,
    ApiError,
    { userId: string; stepName: string; data?: Record<string, any> }
  >({
    mutationFn: ({ userId, stepName, data }) =>
      onboardingService.markStepCompleted(userId, stepName, data),
    onSuccess: (data, { userId }) => {
      // Update progress cache with new data
      queryClient.setQueryData(onboardingKeys.progress(userId), data);

      // Invalidate the query to ensure fresh data on next access
      queryClient.invalidateQueries({ queryKey: onboardingKeys.progress(userId) });
    },
    onError: (error, { userId, stepName }) => {
      console.error(`Failed to complete step ${stepName} for user ${userId}:`, error);

      // Invalidate queries on error to ensure we get fresh data
      queryClient.invalidateQueries({ queryKey: onboardingKeys.progress(userId) });
    },
    ...options,
  });
};

export const useResetProgress = (
  options?: UseMutationOptions<UserProgress, ApiError, string>
) => {
  const queryClient = useQueryClient();

  return useMutation<UserProgress, ApiError, string>({
    mutationFn: (userId: string) => onboardingService.resetProgress(userId),
    onSuccess: (data, userId) => {
      // Update progress cache
      queryClient.setQueryData(onboardingKeys.progress(userId), data);
    },
    ...options,
  });
};

// Draft Queries and Mutations

/**
 * Query hook to get draft data for a specific step
 */
export const useStepDraft = (
  stepName: string,
  options?: Omit<UseQueryOptions<StepDraftResponse, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<StepDraftResponse, ApiError>({
    queryKey: onboardingKeys.stepDraft(stepName),
    queryFn: () => onboardingService.getStepDraft(stepName),
    enabled: !!stepName,
    staleTime: 30 * 1000, // 30 seconds
    ...options,
  });
};

/**
 * Mutation hook to save draft data for a step
 */
export const useSaveStepDraft = (
  options?: UseMutationOptions<{ success: boolean }, ApiError, { stepName: string; draftData: Record<string, any> }>
) => {
  const queryClient = useQueryClient();

  return useMutation<{ success: boolean }, ApiError, { stepName: string; draftData: Record<string, any> }>({
    mutationFn: ({ stepName, draftData }) => onboardingService.saveStepDraft(stepName, draftData),
    onSuccess: (_, { stepName }) => {
      // Invalidate the draft query to get fresh data
      queryClient.invalidateQueries({ queryKey: onboardingKeys.stepDraft(stepName) });
    },
    ...options,
  });
};

/**
 * Mutation hook to delete draft data for a step
 */
export const useDeleteStepDraft = (
  options?: UseMutationOptions<{ success: boolean }, ApiError, string>
) => {
  const queryClient = useQueryClient();

  return useMutation<{ success: boolean }, ApiError, string>({
    mutationFn: (stepName: string) => onboardingService.deleteStepDraft(stepName),
    onSuccess: (_, stepName) => {
      // Invalidate the draft query
      queryClient.invalidateQueries({ queryKey: onboardingKeys.stepDraft(stepName) });
    },
    ...options,
  });
};

/**
 * Custom hook with debounced draft auto-save functionality.
 * Automatically saves draft data after a delay when form data changes.
 */
export const useAutoSaveDraft = (stepName: string, debounceMs: number = 2000) => {
  const saveStepDraft = useSaveStepDraft();
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);

  const saveDraft = useCallback(
    (draftData: Record<string, any>) => {
      // Clear any existing timeout
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }

      // Set a new timeout for debounced save
      timeoutRef.current = setTimeout(() => {
        saveStepDraft.mutate({ stepName, draftData });
      }, debounceMs);
    },
    [stepName, debounceMs, saveStepDraft]
  );

  const saveDraftImmediately = useCallback(
    (draftData: Record<string, any>) => {
      // Clear any pending debounced save
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
      // Save immediately
      saveStepDraft.mutate({ stepName, draftData });
    },
    [stepName, saveStepDraft]
  );

  const cancelPendingSave = useCallback(() => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
      timeoutRef.current = null;
    }
  }, []);

  return {
    saveDraft,
    saveDraftImmediately,
    cancelPendingSave,
    isSaving: saveStepDraft.isPending,
    isError: saveStepDraft.isError,
    error: saveStepDraft.error,
  };
};