import { useMutation } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query';
import { useCallback } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import { useApiClient } from '@/lib/apiClient';
import type { components } from '@/lib/gen';

import type {
  FavoriteResponse,
  ToggleFavoriteHandler,
} from './generationHistoryTypes';
import { generationQueryKeys } from './queryKeys';
import { useToggleFavorite } from './useToggleFavorite';

type ClipMetadataSchema = components['schemas']['ClipMetadataSchema'];

interface SaveAsImageCoverParams {
  clipId: string;
  imageUrl: string;
}

interface SaveAsVideoCoverParams {
  clipId: string;
  videoCoverUploadId: string;
}

export const useSaveAsCover = () => {
  const apiClient = useApiClient();
  const queryClient = useQueryClient();
  const { clips } = useStores();

  const saveAsImageCover = useMutation({
    mutationFn: async ({ clipId, imageUrl }: SaveAsImageCoverParams) => {
      const { data, error } = await apiClient.POST(
        '/api/gen/{gen_id}/set_metadata/',
        {
          params: { path: { gen_id: clipId } },
          body: {
            image_url: imageUrl,
          },
        }
      );

      if (error || !data) {
        throw new Error('Failed to set image cover');
      }

      // Check if the response is an error schema
      if ('error_type' in data) {
        const errorMessage =
          data.moderation_error_message ??
          `Failed to set image cover: ${data.error_type}`;
        throw new Error(errorMessage);
      }

      return data;
    },
    onSuccess: (data, variables) => {
      // Update the MobX store with the new cover URLs
      // data is guaranteed to be ClipMetadataSchema since mutationFn throws on error responses
      const metadata = data as ClipMetadataSchema;
      if (clips.clipById[variables.clipId]) {
        clips.clipById[variables.clipId].image_url = metadata.image_url;
        if (metadata.video_cover_url !== undefined) {
          clips.clipById[variables.clipId].video_cover_url =
            metadata.video_cover_url;
        }
        if (metadata.preview_url !== undefined) {
          clips.clipById[variables.clipId].preview_url = metadata.preview_url;
        }
      }
    },
  });

  const saveAsVideoCover = useMutation({
    mutationFn: async ({
      clipId,
      videoCoverUploadId,
    }: SaveAsVideoCoverParams) => {
      const { data, error } = await apiClient.POST(
        '/api/gen/{gen_id}/set_metadata/',
        {
          params: { path: { gen_id: clipId } },
          body: {
            video_cover_upload_id: videoCoverUploadId,
          },
        }
      );

      if (error || !data) {
        throw new Error('Failed to set video cover');
      }

      // Check if the response is an error schema
      if ('error_type' in data) {
        const errorMessage =
          data.moderation_error_message ??
          `Failed to set video cover: ${data.error_type}`;
        throw new Error(errorMessage);
      }

      return data;
    },
    onSuccess: (data, variables) => {
      // Update the MobX store with the new cover URLs
      // data is guaranteed to be ClipMetadataSchema since mutationFn throws on error responses
      const metadata = data as ClipMetadataSchema;
      if (clips.clipById[variables.clipId]) {
        clips.clipById[variables.clipId].image_url = metadata.image_url;
        clips.clipById[variables.clipId].video_cover_url =
          metadata.video_cover_url;
        clips.clipById[variables.clipId].preview_url = metadata.preview_url;
      }
    },
  });
  // Use shared toggle favorite mutation
  const toggleFavoriteMutation = useToggleFavorite();

  const toggleFavoriteWithCacheUpdate: ToggleFavoriteHandler = useCallback(
    async (
      entityType,
      entityId,
      currentIsLiked,
      clipId
    ): Promise<FavoriteResponse> => {
      const result = await toggleFavoriteMutation.mutateAsync({
        entityType,
        entityId,
        isFavorite: !currentIsLiked,
      });
      // Clear favorites cache so it refetches with updated favorite state
      queryClient.removeQueries({
        queryKey: generationQueryKeys.videoGenerationFavorites(),
      });
      // Clear history cache so it refetches with updated favorite state
      queryClient.removeQueries({
        queryKey: generationQueryKeys.history(clipId),
      });
      return result;
    },
    [toggleFavoriteMutation, queryClient]
  );

  return {
    saveAsImageCover,
    saveAsVideoCover,
    toggleFavorite: toggleFavoriteWithCacheUpdate,
  };
};
