'use client'
import {
  MutationFunction,
  MutationFunctionContext,
  MutationKey,
  useMutation,
  useQueryClient
} from '@tanstack/react-query'
import { AxiosError } from 'axios'
import { useRef } from 'react'
import { toast } from 'react-toastify'
import { CustomUseMutationOptions } from '@/@core/types/api'
import { useTranslations } from 'next-intl'

type CompatibleMutationFunction<TData, TVariable> = (
  variables: TVariable,
  context?: MutationFunctionContext
) => Promise<TData>

export const useCustomMutation = <TVariable = any, TData = any, TError = TData>(
  mutationKey: MutationKey,
  mutationFn: CompatibleMutationFunction<TData, TVariable>,
  options?: CustomUseMutationOptions<TData, AxiosError<TError>, TVariable>
) => {
  const t = useTranslations()
  const queryClient = useQueryClient()

  const toastId = useRef<any>(null)

  const notify = () => (toastId.current = toast.loading(t('COMMON.PROCESSING'), { autoClose: 2000 }))

  const update = (type: 'success' | 'error') => {
    let message = type === 'success' ? options?.promise?.message?.onSuccess : options?.promise?.message?.onError

    if (!options?.promise?.withoutTranslation && message) message = t(message)

    return (
      toastId &&
      toast.update(toastId.current, {
        render: message,
        type,
        autoClose: 3000,
        isLoading: false
      })
    )
  }

  const onMutate = async (variables: TVariable, context: MutationFunctionContext) => {
    if (!options?.withoutToastMessage && options?.toastMessageType === 'promise') notify()
    if (options?.onMutate) options.onMutate(variables, context)
  }

  const onSuccess = async (data: any, variables: any, onMutateResult: unknown, context: MutationFunctionContext) => {
    try {
      if (!options?.withoutToastMessage) {
        if (options?.toastMessageType === 'promise') {
          update('success')
        } else if (Array.isArray(data?.messages)) {
          const messages: string[] = data?.messages
          if (messages?.length > 0) {
            messages?.map(message => toast.success(message))
          }
        } else toast.success(data?.messages)
      }

      if (options?.onSuccess) await options.onSuccess(data, variables, onMutateResult, context)

      if (options?.invalidateQueries) await queryClient.invalidateQueries({ queryKey: options.invalidateQueries })
      if (options?.refetchQueries)
        options.refetchQueries.map(rQ => queryClient.refetchQueries(rQ?.filters, rQ?.options))
    } catch (errors) {
      console.error('🚀 ~ onSuccess error:', errors)
    }
  }

  const onError = async (
    error: AxiosError<any>,
    variables: any,
    onMutateResult: unknown,
    context: MutationFunctionContext
  ): Promise<void> => {
    try {
      if (!options?.withoutToastMessage) {
        const errorData = error?.response?.data as any
        if (options?.toastMessageType === 'promise') {
          update('error')
        } else if (Array.isArray(errorData?.messages)) {
          const messages: string[] = errorData.messages
          if (messages?.length > 0) {
            messages?.map(message => toast.error(message))
          }
        } else if (typeof errorData?.messages === 'string') {
          toast.error(errorData.messages)
        } else if (errorData?.message) {
          toast.error(errorData.message)
        }
      }
      if (options?.onError) await options.onError(error, variables, onMutateResult, context)
    } catch (errors) {
      console.log('🚀 ~ file: useMutation.tsx:103 ~ errors:', errors)
    }
  }
  const mutation = useMutation<TData, AxiosError<TError>, TVariable>({
    mutationKey,
    mutationFn: ((variables, context) => mutationFn(variables, context)) as MutationFunction<TData, TVariable>,
    ...options,
    onError,
    onSuccess,
    onMutate
  })

  return mutation
}
