import type { QueryClient } from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

import { ApiError } from "../../api";
import type { CatalogKind, WorkoutSetInput } from "../../types";
import { useAuth } from "../auth/AuthContext";
import { workoutApi } from "./api";

export async function invalidateWorkoutQueries(queryClient: QueryClient) {
  await Promise.all([
    queryClient.invalidateQueries({ queryKey: ["workout", "active"] }),
    queryClient.invalidateQueries({ queryKey: ["workouts"] }),
    queryClient.invalidateQueries({ queryKey: ["calories"] }),
    queryClient.invalidateQueries({ queryKey: ["progression"] }),
  ]);
}

export function useActiveWorkout() {
  const { auth } = useAuth();
  return useQuery({ queryKey: ["workout", "active"], queryFn: () => workoutApi.active(auth.accessToken) });
}

export function useWorkoutMutations(options: { onStartConflict?: () => void; onFinish?: () => void; onDiscard?: () => void } = {}) {
  const { auth } = useAuth();
  const token = auth.accessToken;
  const queryClient = useQueryClient();

  const refresh = () => invalidateWorkoutQueries(queryClient);

  const startWorkout = useMutation({
    mutationFn: () => workoutApi.start(token),
    onSuccess: refresh,
    onError: async (error) => {
      if (error instanceof ApiError && error.status === 409) {
        await refresh();
        options.onStartConflict?.();
      }
    },
  });

  const addWorkoutItem = useMutation({
    mutationFn: ({ workoutId, sourceId }: { workoutId: string; sourceId: string; kind: CatalogKind }) =>
      workoutApi.addItem(token, workoutId, {
        activity_source_id: sourceId,
        exercise_id: null,
        equipment_id: null,
      }),
    onSuccess: refresh,
  });

  const recordWorkoutSet = useMutation({
    mutationFn: ({ itemId, payload }: { itemId: string; payload: WorkoutSetInput }) => workoutApi.addSet(token, itemId, payload),
    onSuccess: refresh,
  });

  const recordWorkoutSetsBatch = useMutation({
    mutationFn: ({ itemId, sets }: { itemId: string; sets: WorkoutSetInput[] }) => workoutApi.addSetBatch(token, itemId, sets),
    onSuccess: refresh,
  });

  const removeWorkoutItem = useMutation({
    mutationFn: (itemId: string) => workoutApi.removeItem(token, itemId),
    onSuccess: refresh,
  });

  const removeWorkoutSet = useMutation({
    mutationFn: ({ itemId, setId }: { itemId: string; setId: string }) => workoutApi.removeSet(token, itemId, setId),
    onSuccess: refresh,
  });

  const updateWorkoutSet = useMutation({
    mutationFn: ({ setId, payload }: { setId: string; payload: Partial<WorkoutSetInput> }) => workoutApi.updateSet(token, setId, payload),
    onSuccess: refresh,
  });

  const finishWorkout = useMutation({
    mutationFn: ({ workoutId, notes }: { workoutId: string; notes?: string }) => workoutApi.finish(token, workoutId, notes),
    onSuccess: async () => {
      await refresh();
      options.onFinish?.();
    },
  });

  const discardWorkout = useMutation({
    mutationFn: (workoutId: string) => workoutApi.discard(token, workoutId),
    onSuccess: async () => {
      await refresh();
      options.onDiscard?.();
    },
  });

  return {
    startWorkout,
    addWorkoutItem,
    recordWorkoutSet,
    recordWorkoutSetsBatch,
    removeWorkoutItem,
    removeWorkoutSet,
    updateWorkoutSet,
    finishWorkout,
    discardWorkout,
  };
}
