import { useCallback } from 'react'
import { HookFetcher } from '@commerce/utils/types'
import { ValidationError } from '@commerce/utils/errors'
import useCartRemoveItem, {
  RemoveItemInput as UseRemoveItemInput,
} from '@commerce/cart/use-remove-item'

import useCart from './use-cart'

import type { Cart, LineItem, RemoveCartItemBody } from '@commerce/types'
import { checkoutLineItemRemoveMutation } from '@framework/utils/mutations'
import getCheckoutId from '@framework/utils/get-checkout-id'
import { checkoutToCart } from './utils'

const defaultOpts = {
  query: checkoutLineItemRemoveMutation,
}

export type RemoveItemFn<T = any> = T extends LineItem
  ? (input?: RemoveItemInput<T>) => Promise<Cart | null>
  : (input: RemoveItemInput<T>) => Promise<Cart | null>

export type RemoveItemInput<T = any> = T extends LineItem
  ? Partial<UseRemoveItemInput>
  : UseRemoveItemInput

export const fetcher: HookFetcher<Cart | null, any> = async (
  options,
  { itemId, checkoutId },
  fetch
) => {
  const data = await fetch<any>({
    ...defaultOpts,
    ...options,
    variables: { lineItemIds: [itemId], checkoutId },
  })
  return checkoutToCart(data?.checkoutLineItemsRemove)
}

export function extendHook(customFetcher: typeof fetcher) {
  const useRemoveItem = <T extends LineItem | undefined = undefined>(
    item?: T
  ) => {
    const { mutate, data: cart } = useCart()
    const fn = useCartRemoveItem<Cart | null, any>(defaultOpts, customFetcher)
    const removeItem: RemoveItemFn<LineItem> = async (input) => {
      const itemId = input?.id ?? item?.id

      if (!itemId) {
        throw new ValidationError({
          message: 'Invalid input used for this operation',
        })
      }

      const data = await fn({
        checkoutId: getCheckoutId(cart?.id),
        itemId,
      })

      await mutate(data, false)
      return data
    }

    return useCallback(removeItem as RemoveItemFn<T>, [fn, mutate])
  }

  useRemoveItem.extend = extendHook

  return useRemoveItem
}

export default extendHook(fetcher)