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 { normalizeCart } from '../lib/normalize'
import type {
  RemoveCartItemBody,
  Cart,
  BigcommerceCart,
  LineItem,
} from '../types'
import useCart from './use-cart'

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

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, RemoveCartItemBody> = async (
  options,
  { itemId },
  fetch
) => {
  const data = await fetch<BigcommerceCart>({
    ...defaultOpts,
    ...options,
    body: { itemId },
  })
  return normalizeCart(data)
}

export function extendHook(customFetcher: typeof fetcher) {
  const useRemoveItem = <T extends LineItem | undefined = undefined>(
    item?: T
  ) => {
    const { mutate } = useCart()
    const fn = useCartRemoveItem<Cart | null, RemoveCartItemBody>(
      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({ itemId })
      await mutate(data, false)
      return data
    }

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

  useRemoveItem.extend = extendHook

  return useRemoveItem
}

export default extendHook(fetcher)