type SalePricingFields = {
  id: string;
  basePrice: number;
  personalisedPrice: number | null;
  salePrice: number | null;
  saleStartsAt: Date | null;
  saleEndsAt: Date | null;
};

export type ActivePromotion = {
  discountPercent: number;
  scope: 'ALL' | 'SPECIFIC';
  productIds: Set<string>;
};

type PromotionForActiveCheck = {
  discountPercent: number;
  scope: string;
  startsAt: Date | null;
  endsAt: Date | null;
  products: { id: string }[];
};

// Filters raw Promotion rows down to ones whose date window is active right
// now. Call once per request (src/lib/promotions.ts) and pass the result into
// every getEffectivePrice call — never re-derive this per product.
export function getActivePromotions(promotions: PromotionForActiveCheck[], now = new Date()): ActivePromotion[] {
  return promotions
    .filter((p) => (p.startsAt == null || p.startsAt <= now) && (p.endsAt == null || p.endsAt >= now))
    .map((p) => ({
      discountPercent: p.discountPercent,
      scope: p.scope as 'ALL' | 'SPECIFIC',
      productIds: new Set(p.products.map((x) => x.id)),
    }));
}

// Single source of truth for what a product actually costs right now — used
// both for display (src/lib/product.ts) and for the actual amount charged at
// checkout (src/app/api/checkout/route.ts). Never duplicate this logic
// elsewhere. A product's own manual sale price and any active promotions that
// cover it (scope "ALL", or "SPECIFIC" naming this product) all compete —
// whichever produces the lowest price wins, so discounts never stack.
export function getEffectivePrice(
  product: SalePricingFields,
  activePromotions: ActivePromotion[] = [],
  now = new Date(),
  usePersonalisedPrice = false,
) {
  const basePrice = usePersonalisedPrice && product.personalisedPrice != null ? product.personalisedPrice : product.basePrice;
  const candidates = [basePrice];

  const manualSaleActive =
    product.salePrice != null &&
    (product.saleStartsAt == null || product.saleStartsAt <= now) &&
    (product.saleEndsAt == null || product.saleEndsAt >= now);
  if (manualSaleActive) candidates.push(product.salePrice!);

  for (const promo of activePromotions) {
    if (promo.scope === 'ALL' || promo.productIds.has(product.id)) {
      candidates.push(Math.round(basePrice * (1 - promo.discountPercent / 100)));
    }
  }

  const price = Math.min(...candidates);
  const onSale = price < basePrice;

  return {
    onSale,
    price,
    originalPrice: onSale ? basePrice : null,
  };
}
