import $ from 'jquery'
import { notification } from 'ant-design-vue'
import { __ } from '@wordpress/i18n'
import { getI18n, l10nObj } from '@/helper'

const loadedObject = l10nObj()

const STOCK_OUTOFSTOCK = 'outofstock'
const PRODUCT_TYPE_VARIABLE = 'variable'

export interface CartItem {
  id?: number
  collection_id: number
  quantity: number
  product: {
    id: number
    stock: string
    type: string
  }
}

type GetItemKeyFn = (item: CartItem) => number

export interface AddToCartResult {
  successCount: number
  failureCount: number
}

/**
 * Determine whether a wishlist item can be added to cart.
 * Out-of-stock items and variable products without a selected variation
 * are ineligible.
 *
 * @param item             Wishlist item to evaluate.
 * @param selectedVariation Map of item key to chosen variation id.
 * @param getItemKey       Resolves the lookup key used against `selectedVariation`.
 * @return `true` when the item is eligible to be added to cart.
 * @since 1.0.4
 */
function isItemEligible(
  item: CartItem,
  selectedVariation: Record<number, number>,
  getItemKey: GetItemKeyFn
): boolean {
  if (item.product.stock === STOCK_OUTOFSTOCK) return false
  if (item.product.type === PRODUCT_TYPE_VARIABLE && !selectedVariation[getItemKey(item)]) return false
  return true
}

/**
 * Filter wishlist items eligible to be added to cart.
 * Items are excluded if out of stock or if they're variable products
 * with no variation selected.
 */
export function filterEligibleCartItems(
  items: CartItem[],
  selectedVariation: Record<number, number>,
  getItemKey: GetItemKeyFn
): CartItem[] {
  return items.filter((item: CartItem) => isItemEligible(item, selectedVariation, getItemKey))
}

/**
 * Filter wishlist items that are both selected and eligible to be added to cart.
 */
export function filterSelectedCartItems(
  items: CartItem[],
  selectedItems: number[],
  selectedVariation: Record<number, number>,
  getItemKey: GetItemKeyFn
): CartItem[] {
  return items.filter((item: CartItem) => {
    if (!selectedItems.includes(getItemKey(item))) return false
    return isItemEligible(item, selectedVariation, getItemKey)
  })
}

/**
 * Send a single add-to-cart AJAX request.
 * Resolves with `true` on success and `false` on failure, so callers can
 * aggregate per-item outcomes without relying on rejected promises.
 */
export function addSingleCartItem(
  item: CartItem,
  selectedVariation: Record<number, number>,
  getItemKey: GetItemKeyFn
): Promise<boolean> {
  return new Promise<boolean>((resolve) => {
    $.ajax({
      type: 'POST',
      url: loadedObject.ajax.url,
      data: {
        action: 'stwlite_add_to_cart',
        nonce: loadedObject.ajax.nonce,
        collection_id: item.collection_id,
        product_id: item.product.id,
        quantity: item.quantity,
        product_type: item.product.type,
        variation_id: selectedVariation[getItemKey(item)] || 0,
      },
      success: () => resolve(true),
      error: () => resolve(false),
    })
  })
}

/**
 * Add items to the WooCommerce cart one-by-one.
 *
 * Requests must run sequentially because WooCommerce persists the cart in
 * the PHP session; parallel requests each load the same starting cart, append
 * their own item, and save the session back, causing earlier additions to be
 * silently dropped (classic lost-update race).
 */
export async function addCartItemsSequentially(
  items: CartItem[],
  selectedVariation: Record<number, number>,
  getItemKey: GetItemKeyFn
): Promise<AddToCartResult> {
  let successCount = 0
  let failureCount = 0

  for (const item of items) {
    const ok = await addSingleCartItem(item, selectedVariation, getItemKey)
    if (ok) {
      successCount++
    } else {
      failureCount++
    }
  }

  return { successCount, failureCount }
}

/**
 * Surface the outcome of a bulk add-to-cart as a user-facing notification.
 * Distinguishes all-failed, partial-failure, and all-succeeded so users are
 * not misled when the underlying requests silently drop an item.
 */
export function notifyAddToCartResult(successCount: number, failureCount: number): void {
  if (successCount === 0 && failureCount > 0) {
    notification.error({
      message: getI18n('add_to_cart_failed', __('Failed to add items to cart. Please try again.', 'saveto-wishlist-lite-for-woocommerce')),
      class: 'wishlist-lists-error-notification',
    })
    return
  }

  if (failureCount > 0) {
    notification.warning({
      message: getI18n('some_items_failed', __('Some items could not be added to cart.', 'saveto-wishlist-lite-for-woocommerce')),
      class: 'wishlist-lists-warning-notification',
    })
    return
  }

  notification.success({
    message: getI18n('all_added_to_cart', __('Items added to cart.', 'saveto-wishlist-lite-for-woocommerce')),
    class: 'wishlist-lists-success-notification',
  })
}

/**
 * Finalize a bulk add-to-cart flow: show the outcome notification, and when
 * at least one item succeeded, refresh WooCommerce cart fragments and the
 * wishlist view.
 */
export function finalizeAddToCart(result: AddToCartResult, refreshWishlist: () => void): void {
  notifyAddToCartResult(result.successCount, result.failureCount)

  if (result.successCount > 0) {
    document.body.dispatchEvent(new CustomEvent('wc_fragment_refresh'))
    refreshWishlist()
  }
}
