/**
 * Shared order-pricing composer.
 *
 * Both `orders.service.createOrder` (used by Web Chat + WhatsApp) and
 * `storefront.service.createStorefrontOrder` run their pricing through this
 * helper so they always honor the same canonical pipeline:
 *
 *     subtotal
 *       - coupon discount
 *       - loyalty discount     (capped against post-coupon subtotal)
 *       - gift card applied    (capped against post-loyalty subtotal,
 *                               plus the projected tax when the gift card
 *                               settings use redemption_rule = 'total')
 *       + tax                  (computed on the post-gift-card subtotal)
 *       = total
 *
 * The composer is pure math — DB-bound steps (applyCoupon, loyalty
 * previewRedeem, gift-card lock) live in the calling service. Each caller
 * runs those steps in the order above, then asks this composer for the
 * authoritative {tax, total, intermediate subtotals} to persist and to
 * surface to the dashboard / customer email.
 */

export const TAX_RATE = 0.08;

const round2 = (n: number): number => Math.round(n * 100) / 100;

export interface PricingComposeInput {
  /** Pre-discount sum of (price * qty) for the cart. */
  subtotal: number;
  /** Coupon discount returned by `applyCoupon`. */
  couponDiscount?: number;
  /** Loyalty discount returned by `previewRedeem` (run AFTER coupon). */
  loyaltyDiscount?: number;
  /** Gift card amount actually applied — caller computes via
   *  `computeGiftCardOffset` so the cap honors redemption_rule. */
  giftCardApplied?: number;
  /** Override the default 8% tax rate (used in tests). */
  taxRate?: number;
}

export interface PricingComposeResult {
  subtotal: number;
  couponDiscount: number;
  loyaltyDiscount: number;
  giftCardApplied: number;
  /** Subtotal after coupon discount. Loyalty preview must use this. */
  subtotalAfterCoupon: number;
  /** Subtotal after coupon + loyalty. Gift card cap must use this. */
  subtotalAfterLoyalty: number;
  /** Subtotal after coupon + loyalty + gift card. Tax is computed on this. */
  subtotalAfterGiftCard: number;
  tax: number;
  total: number;
}

/**
 * Pure pricing composer. Each discount is clamped so it cannot exceed
 * the running subtotal. Tax is always recomputed on the post-gift-card
 * subtotal so persisted `subtotal/tax/total` always agree with the
 * displayed line items.
 */
export function composeOrderPricing(input: PricingComposeInput): PricingComposeResult {
  const taxRate = input.taxRate ?? TAX_RATE;
  const subtotal = round2(Math.max(0, Number(input.subtotal) || 0));

  const couponDiscount = round2(
    Math.max(0, Math.min(Number(input.couponDiscount) || 0, subtotal)),
  );
  const subtotalAfterCoupon = round2(Math.max(0, subtotal - couponDiscount));

  const loyaltyDiscount = round2(
    Math.max(0, Math.min(Number(input.loyaltyDiscount) || 0, subtotalAfterCoupon)),
  );
  const subtotalAfterLoyalty = round2(Math.max(0, subtotalAfterCoupon - loyaltyDiscount));

  const giftCardApplied = round2(
    Math.max(0, Math.min(Number(input.giftCardApplied) || 0, subtotalAfterLoyalty)),
  );
  const subtotalAfterGiftCard = round2(Math.max(0, subtotalAfterLoyalty - giftCardApplied));

  const tax = round2(subtotalAfterGiftCard * taxRate);
  const total = round2(subtotalAfterGiftCard + tax);

  return {
    subtotal,
    couponDiscount,
    loyaltyDiscount,
    giftCardApplied,
    subtotalAfterCoupon,
    subtotalAfterLoyalty,
    subtotalAfterGiftCard,
    tax,
    total,
  };
}

/**
 * Compute how much of a gift card to apply against the running order.
 *
 * In this pipeline gift cards reduce the taxable subtotal (they are
 * applied BEFORE tax), so the ceiling is the post-loyalty subtotal
 * regardless of `gift_card_settings.redemption_rule`. The 'total' rule
 * (legacy: card could cover the post-tax bill) is preserved as an
 * accepted setting for backward compatibility but no longer changes
 * the cap — the strict pipeline always treats the cap as `subtotal -
 * coupon - loyalty`. Callers still pass `redemptionRule` so the helper
 * can be evolved later without another signature change.
 */
export function computeGiftCardOffset(input: {
  subtotalAfterLoyalty: number;
  cardBalance: number;
  redemptionRule?: 'subtotal' | 'total';
  taxRate?: number;
}): number {
  const base = Math.max(0, round2(input.subtotalAfterLoyalty));
  return round2(Math.max(0, Math.min(input.cardBalance, base)));
}
