import { useCallback } from 'react'
import debounce from 'lodash.debounce'
import type { HookFetcher } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors'
import useCartUpdateItem from '@commerce/cart/use-update-item'
import { normalizeCart } from '../lib/normalize'
import type {
  Cart,
  BigcommerceCart,
  UpdateCartItemBody,
  UpdateCartItemInput,
} from '../types'
import { fetcher as removeFetcher } from './use-remove-item'
import useCart from './use-cart'

const defaultOpts = {
  url: '/api/bigcommerce/cart',
  method: 'PUT',
}

export const fetcher: HookFetcher<Cart | null, UpdateCartItemBody> = async (
  options,
  { itemId, item },
  fetch
) => {
  if (Number.isInteger(item.quantity)) {
    // Also allow the update hook to remove an item if the quantity is lower than 1
    if (item.quantity! < 1) {
      return removeFetcher(null, { itemId }, fetch)
    }
  } else if (item.quantity) {
    throw new CommerceError({
      message: 'The item quantity has to be a valid integer',
    })
  }

  const data = await fetch<BigcommerceCart>({
    ...defaultOpts,
    ...options,
    body: { itemId, item },
  })

  return normalizeCart(data)
}

function extendHook(customFetcher: typeof fetcher, cfg?: { wait?: number }) {
  const useUpdateItem = (item?: any) => {
    const { mutate } = useCart()
    const fn = useCartUpdateItem<Cart | null, UpdateCartItemBody>(
      defaultOpts,
      customFetcher
    )

    return useCallback(
      debounce(async (input: UpdateCartItemInput) => {
        console.log('INPUT', input, {
          itemId: input.id ?? item?.id,
          item: {
            productId: input.productId ?? item?.product_id,
            variantId: input.productId ?? item?.variant_id,
            quantity: input.quantity,
          },
        })
        const data = await fn({
          itemId: input.id ?? item?.id,
          item: {
            productId: input.productId ?? item?.product_id,
            variantId: input.productId ?? item?.variant_id,
            quantity: input.quantity,
          },
        })
        await mutate(data, false)
        return data
      }, cfg?.wait ?? 500),
      [fn, mutate]
    )
  }

  useUpdateItem.extend = extendHook

  return useUpdateItem
}

export default extendHook(fetcher)
