// Central discount/pricing rules, used by both checkout (source of truth) and
// the storefront (display). Keep this the ONLY place discount math happens.

export type PricedProduct = {
  basePrice: number;
  salePrice: number | null;
  category: { discountPercent: number | null } | null;
};

export type BulkTier = { minQty: number; discountPercent: number };

/**
 * Effective unit price before any variant delta or Buy-X-Get-Y adjustment.
 * Priority (first match wins, does not stack): product sale price > category
 * discount % > best matching bulk tier > full base price. Kept deterministic
 * on purpose — stacking all of these automatically would be easy to get
 * wrong and would directly change what a customer is charged.
 */
export function effectiveUnitPrice(product: PricedProduct, quantity: number, bulkTiers: BulkTier[]): { price: number; label: string | null } {
  if (product.salePrice !== null && product.salePrice > 0 && product.salePrice < product.basePrice) {
    return { price: product.salePrice, label: "Sale price" };
  }
  if (product.category?.discountPercent) {
    const pct = product.category.discountPercent;
    return { price: Math.round(product.basePrice * (1 - pct / 100)), label: `${pct}% category discount` };
  }
  const bestTier = bulkTiers
    .filter((t) => quantity >= t.minQty)
    .sort((a, b) => b.minQty - a.minQty)[0];
  if (bestTier) {
    return { price: Math.round(product.basePrice * (1 - bestTier.discountPercent / 100)), label: `${bestTier.discountPercent}% bulk discount` };
  }
  return { price: product.basePrice, label: null };
}

/**
 * Buy-X-Get-Y: for every complete (buyQty + getQty) group in the quantity
 * ordered, getQty units are discounted by getDiscountPct. Returns the total
 * paise to deduct from the line (computed against the already-discounted
 * unit price, since it targets specific units within the line).
 */
export function buyXGetYDeduction(quantity: number, unitPrice: number, offer: { buyQty: number; getQty: number; getDiscountPct: number } | null): number {
  if (!offer || offer.buyQty <= 0 || offer.getQty <= 0) return 0;
  const groupSize = offer.buyQty + offer.getQty;
  const completeGroups = Math.floor(quantity / groupSize);
  const discountedUnits = completeGroups * offer.getQty;
  return Math.round(discountedUnits * unitPrice * (offer.getDiscountPct / 100));
}

/**
 * Order-level discount: coupon vs. any currently-active festival offer,
 * whichever gives the bigger reduction. The two never stack.
 */
export function bestOrderDiscount(
  subtotal: number,
  coupon: { type: string; value: number } | null,
  festivalPercent: number | null
): { amount: number; label: string | null } {
  const couponAmount = coupon ? (coupon.type === "percent" ? Math.round(subtotal * (coupon.value / 100)) : Math.min(coupon.value, subtotal)) : 0;
  const festivalAmount = festivalPercent ? Math.round(subtotal * (festivalPercent / 100)) : 0;

  if (couponAmount === 0 && festivalAmount === 0) return { amount: 0, label: null };
  if (couponAmount >= festivalAmount) return { amount: couponAmount, label: "Coupon" };
  return { amount: festivalAmount, label: "Festival offer" };
}
