import { PaymentType } from '@generated/swagger/checkout-api';
import { CustomerTypeAnalysis, OrderOptionsAnalysis } from '../models';

/**
 * Payment type constants used in checkout logic.
 *
 * @remarks
 * These constants represent different payment methods in the checkout system:
 * - FREE: Loyalty/reward orders with no charge (value: 2)
 * - CASH: Cash payment for in-store pickup or take away (value: 4)
 * - INVOICE: Invoice payment for delivery and download orders (value: 128)
 */
export const PaymentTypes = {
  /** Free payment for loyalty/reward items (value: 2) */
  FREE: 2 as PaymentType,
  /** Cash payment for in-store transactions (value: 4) */
  CASH: 4 as PaymentType,
  /** Invoice payment for delivery and digital orders (value: 128) */
  INVOICE: 128 as PaymentType,
} as const;

/**
 * Determines if payer information should be set based on order options and customer type.
 *
 * @remarks
 * Pure business logic function that returns true when:
 * - Customer is B2B (business customer)
 * - Order contains B2B delivery items
 * - Order contains standard delivery items
 * - Order contains digital delivery items
 * - Order contains download items
 *
 * Payer is required for invoicing and delivery scenarios where payment
 * responsibility may differ from the buyer.
 *
 * @param options - Analysis result of shopping cart items
 * @param customer - Analysis result of customer type characteristics
 * @returns true if payer should be set, false otherwise
 *
 * @example
 * ```typescript
 * const options = { hasDelivery: true, hasPickUp: false, ... };
 * const customer = { isB2B: false, isOnline: true, ... };
 * const needsPayer = shouldSetPayer(options, customer);
 * // Returns: true (delivery requires payer)
 * ```
 */
export function shouldSetPayer(
  options: OrderOptionsAnalysis,
  customer: CustomerTypeAnalysis,
): boolean {
  return (
    customer.isB2B ||
    options.hasB2BDelivery ||
    options.hasDelivery ||
    options.hasDigDelivery ||
    options.hasDownload
  );
}

/**
 * Determines if destination update is needed based on order types present.
 *
 * @remarks
 * Pure validation function that returns true when the order contains
 * any delivery or download items that require destination/shipping information:
 * - Download orders
 * - Standard delivery orders
 * - Digital delivery orders
 * - B2B delivery orders
 *
 * Used to decide whether to call the destination update API endpoint.
 *
 * @param options - Analysis result of shopping cart items
 * @returns true if destination needs to be updated, false otherwise
 *
 * @example
 * ```typescript
 * const options = { hasDelivery: true, hasTakeAway: true, ... };
 * const needsUpdate = needsDestinationUpdate(options);
 * // Returns: true (delivery requires destination)
 * ```
 */
export function needsDestinationUpdate(
  options: OrderOptionsAnalysis,
): boolean {
  return (
    options.hasDownload ||
    options.hasDelivery ||
    options.hasDigDelivery ||
    options.hasB2BDelivery
  );
}

/**
 * Determines the appropriate payment type based on order types and item characteristics.
 *
 * @remarks
 * Pure calculation function that determines payment type using this priority:
 *
 * 1. **FREE (2)**: All items have non-zero loyalty.value (reward/loyalty redemption)
 * 2. **INVOICE (128)**: Order contains delivery or download items (requires invoicing)
 * 3. **CASH (4)**: Default for in-store pickup or take away orders
 *
 * Business Rules:
 * - Loyalty orders are always free, regardless of other order types
 * - Delivery/download orders always require invoice payment
 * - In-store orders (pickup, take away) use cash payment
 *
 * @param options - Analysis result with order types and unwrapped shopping cart items
 * @returns Payment type constant (FREE=2, CASH=4, INVOICE=128)
 *
 * @example
 * ```typescript
 * // Loyalty order (all items have loyalty value)
 * const loyaltyOptions = {
 *   items: [{ loyalty: { value: 500 } }, { loyalty: { value: 300 } }],
 *   hasDelivery: false,
 *   ...
 * };
 * determinePaymentType(loyaltyOptions); // Returns: 2 (FREE)
 *
 * // Delivery order
 * const deliveryOptions = {
 *   items: [{ loyalty: { value: 0 } }],
 *   hasDelivery: true,
 *   ...
 * };
 * determinePaymentType(deliveryOptions); // Returns: 128 (INVOICE)
 *
 * // In-store pickup
 * const pickupOptions = {
 *   items: [{ loyalty: { value: 0 } }],
 *   hasPickUp: true,
 *   hasDelivery: false,
 *   ...
 * };
 * determinePaymentType(pickupOptions); // Returns: 4 (CASH)
 * ```
 */
export function determinePaymentType(
  options: OrderOptionsAnalysis,
): PaymentType {
  const needsInvoice =
    options.hasDownload ||
    options.hasDelivery ||
    options.hasDigDelivery ||
    options.hasB2BDelivery;

  // If all ShoppingCartItems have the property loyalty.value set and is not 0, set to FREE
  // Note: empty array returns false (no loyalty items to qualify for free)
  if (
    options.items.length > 0 &&
    options.items.every(
      (item) =>
        typeof item.loyalty?.value === 'number' && item.loyalty.value !== 0,
    )
  ) {
    return PaymentTypes.FREE;
  }

  return needsInvoice ? PaymentTypes.INVOICE : PaymentTypes.CASH;
}
