import {
  keepPreviousData,
  useMutation,
  useQuery,
  useQueryClient,
} from "@tanstack/react-query";
import {
  type AdjustBalanceInput,
  type CreateNonPeriodicExpenseInput,
  type CreatePeriodicExpenseInput,
  type CreateWalletInput,
  type DepositInput,
  type TransferInput,
  type WalletMovementsFilter,
  createNonPeriodicExpense as createNonPeriodicExpenseApi,
  createPeriodicExpense as createPeriodicExpenseApi,
  deletePeriodicExpense as deletePeriodicExpenseApi,
  depositWallet as depositWalletApi,
  adjustBalance as adjustBalanceApi,
  fetchQuotes,
  generateMonthlyExpense as generateMonthlyExpenseApi,
  getDailyMinMax,
  getDailyQuotes,
  getExpenses,
  generateTelegramCode,
  getHistoricalMinMax,
  getMonthlyPayedTotal,
  getMonthlyTotals,
  getPendingUpcomingExpenses,
  getPeriodicExpenses,
  getQuoteHistory,
  getQuotes,
  getTelegramStatus,
  getTotalPending,
  getWalletMovements,
  getWalletMovementsFiltered,
  getWallets,
  setDefaultWallet as setDefaultWalletApi,
  importExpenses,
  importPeriodicExpenses,
  type PayExpenseInput,
  payExpense as payExpenseApi,
  type UpdateExpenseInput,
  updateExpense as updateExpenseApi,
  updatePeriodicExpense as updatePeriodicExpenseApi,
  createWallet as createWalletApi,
  updateWallet as updateWalletApi,
  deleteWallet as deleteWalletApi,
  transferWallet as transferWalletApi,
} from "./api";

export const quoteKeys = {
  all: ["quotes"] as const,
  history: (type: string, startDate: string, endDate: string) =>
    ["quotes", type, "history", startDate, endDate] as const,
  minMax: (type: string, startDate: string, endDate: string) =>
    ["quotes", type, "minMax", startDate, endDate] as const,
  daily: (type: string, startDate: string, endDate: string) =>
    ["quotes", type, "daily", startDate, endDate] as const,
  historicalMinMax: (type: string) =>
    ["quotes", type, "historicalMinMax"] as const,
};

export function useQuotes() {
  return useQuery({
    queryKey: quoteKeys.all,
    queryFn: getQuotes,
    staleTime: 30_000,
    refetchInterval: 60_000,
  });
}

export function useFetchQuotes() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: fetchQuotes,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: quoteKeys.all });
    },
  });
}

export function useQuoteHistory(
  type: string,
  startDate: string,
  endDate: string,
) {
  return useQuery({
    queryKey: quoteKeys.history(type, startDate, endDate),
    queryFn: () => getQuoteHistory(type, startDate, endDate),
    staleTime: 30_000,
    refetchInterval: 60_000,
  });
}

export function useDailyMinMax(
  type: string,
  startDate: string,
  endDate: string,
) {
  return useQuery({
    queryKey: quoteKeys.minMax(type, startDate, endDate),
    queryFn: () => getDailyMinMax(type, startDate, endDate),
    staleTime: 30_000,
    refetchInterval: 60_000,
  });
}

export function useDailyQuotes(
  type: string,
  startDate: string,
  endDate: string,
) {
  return useQuery({
    queryKey: quoteKeys.daily(type, startDate, endDate),
    queryFn: () => getDailyQuotes(type, startDate, endDate),
    staleTime: 30_000,
    refetchInterval: 60_000,
  });
}

export function useHistoricalMinMax(type: string) {
  return useQuery({
    queryKey: quoteKeys.historicalMinMax(type),
    queryFn: () => getHistoricalMinMax(type),
    staleTime: 30_000,
  });
}

// Expenses

export const expenseKeys = {
  periodic: ["periodic-expenses"] as const,
  all: ["expenses"] as const,
  byFilters: (
    status: string,
    page: number,
    pageSize: number,
    periodicExpenseId?: number,
    search?: string,
  ) => ["expenses", status, page, pageSize, periodicExpenseId, search] as const,
  monthlyTotal: (year: number, month: number) =>
    ["expenses", "monthly-total", year, month] as const,
  monthlyTotals: (year: number, month: number) =>
    ["expenses", "totals", year, month] as const,
  totalPending: ["expenses", "pending-total"] as const,
  pendingUpcoming: ["expenses", "pending-upcoming"] as const,
};

export function usePeriodicExpenses() {
  return useQuery({
    queryKey: expenseKeys.periodic,
    queryFn: getPeriodicExpenses,
  });
}

export function useCreatePeriodicExpense() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (data: CreatePeriodicExpenseInput) =>
      createPeriodicExpenseApi(data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: expenseKeys.periodic });
    },
  });
}

export function useUpdatePeriodicExpense() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: ({
      id,
      data,
    }: {
      id: number;
      data: CreatePeriodicExpenseInput;
    }) => updatePeriodicExpenseApi(id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: expenseKeys.periodic });
    },
  });
}

export function useDeletePeriodicExpense() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (id: number) => deletePeriodicExpenseApi(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: expenseKeys.periodic });
    },
  });
}

export function useGenerateMonthlyExpense() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (id: number) => generateMonthlyExpenseApi(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: expenseKeys.all });
    },
  });
}

export function useExpenses(
  status: string,
  page: number = 1,
  pageSize: number = 10,
  periodicExpenseId?: number,
  search?: string,
) {
  return useQuery({
    queryKey: expenseKeys.byFilters(
      status,
      page,
      pageSize,
      periodicExpenseId,
      search,
    ),
    placeholderData: keepPreviousData,
    queryFn: () =>
      getExpenses(
        status === "all" ? undefined : status,
        page,
        pageSize,
        periodicExpenseId,
        search,
      ),
  });
}

export function useMonthlyTotals(year: number, month: number) {
  return useQuery({
    queryKey: expenseKeys.monthlyTotals(year, month),
    queryFn: () => getMonthlyTotals(year, month),
  });
}

export function usePendingUpcomingExpenses() {
  return useQuery({
    queryKey: expenseKeys.pendingUpcoming,
    queryFn: getPendingUpcomingExpenses,
  });
}

export function useTotalPending() {
  return useQuery({
    queryKey: expenseKeys.totalPending,
    queryFn: getTotalPending,
  });
}

export function useMonthlyPayedTotal(year: number, month: number) {
  return useQuery({
    queryKey: expenseKeys.monthlyTotal(year, month),
    queryFn: () => getMonthlyPayedTotal(year, month),
  });
}

export function useCreateNonPeriodicExpense() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (data: CreateNonPeriodicExpenseInput) =>
      createNonPeriodicExpenseApi(data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: expenseKeys.all });
      queryClient.invalidateQueries({ queryKey: walletKeys.all });
    },
  });
}

export function useImportExpenses() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (file: File) => importExpenses(file),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: expenseKeys.all });
    },
  });
}

export function useImportPeriodicExpenses() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (file: File) => importPeriodicExpenses(file),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: expenseKeys.periodic });
    },
  });
}

export function usePayExpense() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: ({ id, data }: { id: number; data: PayExpenseInput }) =>
      payExpenseApi(id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: expenseKeys.all });
      queryClient.invalidateQueries({ queryKey: walletKeys.all });
    },
  });
}

export function useUpdateExpense() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: ({ id, data }: { id: number; data: UpdateExpenseInput }) =>
      updateExpenseApi(id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: expenseKeys.all });
    },
  });
}

// Wallets

export const walletKeys = {
  all: ["wallets"] as const,
  movements: (id: number) => ["wallets", id, "movements"] as const,
  movementsFiltered: (filter: WalletMovementsFilter) =>
    ["wallets", "movements", filter] as const,
};

export function useWallets() {
  return useQuery({
    queryKey: walletKeys.all,
    queryFn: getWallets,
    staleTime: 30_000,
  });
}

export function useCreateWallet() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (data: CreateWalletInput) => createWalletApi(data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: walletKeys.all });
    },
  });
}

export function useUpdateWallet() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: ({
      id,
      data,
    }: {
      id: number;
      data: { name: string; currency: string };
    }) => updateWalletApi(id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: walletKeys.all });
    },
  });
}

export function useDeleteWallet() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (id: number) => deleteWalletApi(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: walletKeys.all });
    },
  });
}

export function useSetDefaultWallet() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (id: number) => setDefaultWalletApi(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: walletKeys.all });
    },
  });
}

export function useDepositWallet() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: ({ id, data }: { id: number; data: DepositInput }) =>
      depositWalletApi(id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: walletKeys.all });
    },
  });
}

export function useAdjustBalance() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: ({ id, data }: { id: number; data: AdjustBalanceInput }) =>
      adjustBalanceApi(id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: walletKeys.all });
    },
  });
}

export function useTransferWallet() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (data: TransferInput) => transferWalletApi(data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: walletKeys.all });
    },
  });
}

export function useWalletMovements(id: number) {
  return useQuery({
    queryKey: walletKeys.movements(id),
    queryFn: () => getWalletMovements(id),
  });
}

export function useWalletMovementsFiltered(filter: WalletMovementsFilter) {
  return useQuery({
    queryKey: walletKeys.movementsFiltered(filter),
    placeholderData: keepPreviousData,
    queryFn: () => getWalletMovementsFiltered(filter),
  });
}

// Telegram

export function useTelegramStatus() {
  return useQuery({
    queryKey: ["telegram", "status"],
    queryFn: getTelegramStatus,
    staleTime: 30_000,
  });
}

export function useGenerateTelegramCode() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: generateTelegramCode,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["telegram", "status"] });
    },
  });
}
