import { type InfiniteData, useMutation } from 'react-query';

import { queryClient } from 'src/config/react-query';

import { pathsKeys } from '../queries';
import { updatePartialPath } from '../services';
import {
  type Path,
  type PathStatusType,
  type PreviousPathsDataContext,
} from '../types';

import { type TSuccess } from './useGetPaths';

export const useUpdatePathStatus = (pathId: number | null) => {
  return useMutation({
    mutationFn: (status: PathStatusType) => {
      if (!pathId) {
        throw new Error('[useUpdatePathStatus] - Path ID is required');
      }
      return updatePartialPath(pathId, { status });
    },
    onMutate: async (newStatus): Promise<PreviousPathsDataContext> => {
      // Cancel queries
      await queryClient.cancelQueries(pathsKeys.paths.all());
      if (pathId) await queryClient.cancelQueries(pathsKeys.detail(pathId));

      // Snapshot paths list
      const pathsQueries = queryClient.getQueriesData<InfiniteData<TSuccess>>(
        pathsKeys.paths.all(),
      );

      // Snapshot path detail
      let previousDetail: Path | undefined;
      if (pathId) {
        previousDetail = queryClient.getQueryData(pathsKeys.detail(pathId));
      }

      // Optimistically update path list
      pathsQueries.forEach(([queryKey, data]) => {
        if (!data) return;

        queryClient.setQueryData(queryKey, {
          ...data,
          pages: data.pages.map(page => ({
            ...page,
            data: {
              ...page.data,
              learningPaths: {
                ...page.data.learningPaths,
                items: page.data.learningPaths.items.map(path =>
                  path.id === pathId ? { ...path, status: newStatus } : path,
                ),
              },
            },
          })),
        });
      });

      // Optimistically update path detail
      if (pathId && previousDetail) {
        queryClient.setQueryData(pathsKeys.detail(pathId), {
          ...previousDetail,
          status: newStatus,
        });
      }

      return { previousPathsQueries: pathsQueries, previousDetail };
    },
    onError: (_error, _newStatus, context) => {
      if (!context) return;

      // Rollback paths list
      context.previousPathsQueries.forEach(([queryKey, data]) => {
        if (data) queryClient.setQueryData(queryKey, data);
      });

      // Rollback path detail
      if (pathId && context.previousDetail) {
        queryClient.setQueryData(
          pathsKeys.detail(pathId),
          context.previousDetail,
        );
      }
    },
    onSettled: () => {
      // Final invalidation
      queryClient.invalidateQueries(pathsKeys.paths.all());
      if (pathId) {
        queryClient.removeQueries(pathsKeys.detail(pathId));
      }
    },
  });
};
