"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AddonDiscountCalculator = void 0;
const core_1 = require("@roomstay/core");
/**
 * For `flatQuantity` and `flatQuantityPerStay` promo codes, discount allocation is SEQUENTIAL:
 * The discount is consumed in this order:
 * 1. Room rates
 * 2. First addon added to basket
 * 3. Second addon added to basket
 * 4. Etc
 *
 * For `flatPercent` types, order doesn't matter as each addon gets its own percentage discount.
 */
class AddonDiscountCalculator {
    /**
     * Calculate total price of all addons with promo code discounts applied.
     * Discounts are applied sequentially for flatQuantityPerStay promo codes.
     *
     * @param addonRows - Array of basket addon rows (ORDER MATTERS for flatQuantityPerStay!)
     * @param roomRows - Array of basket room rows
     * @param promoCodeDetails - Promo code details from basket context
     * @returns Total price of all addons after discounts
     */
    static calculateTotal(addonRows, roomRows, promoCodeDetails) {
        if (!(promoCodeDetails === null || promoCodeDetails === void 0 ? void 0 : promoCodeDetails.applyToAddons)) {
            return addonRows.reduce((total, row) => total + row.getTotalPrice(), 0);
        }
        const individualDiscounts = this.calculateIndividualDiscounts(addonRows, roomRows, promoCodeDetails);
        return individualDiscounts.reduce((total, { addon, discount }) => {
            return total + addon.getTotalPrice() - discount;
        }, 0);
    }
    /**
     * Calculate discount for each addon individually with remaining discount tracking.
     * Useful for displaying discounts in the UI where you need to show each addon's
     * discount separately.
     *
     * @param addonRows - Array of basket addon rows (ORDER MATTERS!)
     * @param roomRows - Array of basket room rows
     * @param promoCodeDetails - Promo code details
     * @returns Array of objects with addon, its discount, and remaining discount available
     */
    static calculateIndividualDiscounts(addonRows, roomRows, promoCodeDetails) {
        if (!(promoCodeDetails === null || promoCodeDetails === void 0 ? void 0 : promoCodeDetails.applyToAddons)) {
            return addonRows.map((addon) => ({ addon, discount: 0, remainingDiscount: 0 }));
        }
        const { totalDiscountAvailable, runningDiscount: initialRunningDiscount } = this.getDiscountInfo(roomRows, promoCodeDetails);
        let runningDiscount = initialRunningDiscount;
        const results = [];
        for (const addon of addonRows) {
            const remainingFixedDiscount = this.getRemainingFixedDiscount(promoCodeDetails, totalDiscountAvailable, runningDiscount);
            const discount = addon.getDiscountAmount(promoCodeDetails, remainingFixedDiscount);
            results.push({ addon, discount, remainingDiscount: remainingFixedDiscount });
            runningDiscount += discount;
        }
        return results;
    }
    /**
     * Calculate discount for an addon being previewed (not yet in basket).
     * This is used in the addon selection UI to show what discount would apply.
     *
     * For flatQuantityPerStay promos, this calculates the remaining discount after
     * accounting for rooms and OTHER addons already in the basket.
     *
     * @param basePrice - Base price of the addon (before discount, before fees)
     * @param addonRows - Array of basket addon rows (addons already in basket)
     * @param roomRows - Array of basket room rows
     * @param promoCodeDetails - Promo code details
     * @returns Discount amount that would apply to this addon
     */
    static calculatePreviewDiscount(basePrice, addonRows, roomRows, promoCodeDetails) {
        if (!(promoCodeDetails === null || promoCodeDetails === void 0 ? void 0 : promoCodeDetails.applyToAddons) || basePrice <= 0) {
            return 0;
        }
        switch (promoCodeDetails.discountType) {
            case core_1.EPromoCodeDiscountType.FlatPercent:
                return Math.round(basePrice * (promoCodeDetails.discountAmount / 100));
            case core_1.EPromoCodeDiscountType.FlatQuantity:
            case core_1.EPromoCodeDiscountType.FlatQuantityPerStay: {
                const { totalDiscountAvailable, runningDiscount: initialRunningDiscount } = this.getDiscountInfo(roomRows, promoCodeDetails);
                // Calculate discount consumed by other addons in basket
                let runningDiscount = initialRunningDiscount;
                addonRows.forEach((row) => {
                    const addonRemainingDiscount = this.getRemainingFixedDiscount(promoCodeDetails, totalDiscountAvailable, runningDiscount);
                    const addonDiscount = row.getDiscountAmount(promoCodeDetails, addonRemainingDiscount);
                    runningDiscount += addonDiscount;
                });
                // Calculate remaining discount for this preview addon
                const remainingDiscount = this.getRemainingFixedDiscount(promoCodeDetails, totalDiscountAvailable, runningDiscount);
                return Math.min(remainingDiscount, basePrice);
            }
            default:
                return 0;
        }
    }
    /**
     * Get discount info including total available and initial running discount from rooms.
     *
     * @param roomRows - Array of basket room rows
     * @param promoCodeDetails - Promo code details
     * @returns Object with totalDiscountAvailable and runningDiscount (from rooms)
     */
    static getDiscountInfo(roomRows, promoCodeDetails) {
        const nights = roomRows.length > 0 ? roomRows[0].getNumberOfDays() : 0;
        const roomDiscount = this.calculateRoomDiscount(roomRows);
        const totalDiscountAvailable = promoCodeDetails.discountType === core_1.EPromoCodeDiscountType.FlatQuantity ? promoCodeDetails.discountAmount * nights : promoCodeDetails.discountAmount;
        return {
            totalDiscountAvailable,
            runningDiscount: roomDiscount,
        };
    }
    /**
     * Calculate remaining fixed discount available.
     *
     * @param promoCodeDetails - Promo code details
     * @param totalDiscountAvailable - Total discount available
     * @param runningDiscount - Discount already consumed
     * @returns Remaining discount available (0 for FlatPercent)
     */
    static getRemainingFixedDiscount(promoCodeDetails, totalDiscountAvailable, runningDiscount) {
        if (promoCodeDetails.discountType === core_1.EPromoCodeDiscountType.FlatQuantity || promoCodeDetails.discountType === core_1.EPromoCodeDiscountType.FlatQuantityPerStay) {
            return Math.max(0, totalDiscountAvailable - runningDiscount);
        }
        return 0;
    }
    /**
     * Calculate total discount already consumed by room rates.
     * This is used as the starting point for addon discount calculations.
     *
     * @param roomRows - Array of basket room rows
     * @returns Total discount amount consumed by all rooms
     */
    static calculateRoomDiscount(roomRows) {
        return roomRows.reduce((total, row) => {
            const rate = row.getRate();
            return total + ((rate === null || rate === void 0 ? void 0 : rate.getTotalDiscount()) || 0);
        }, 0);
    }
}
exports.AddonDiscountCalculator = AddonDiscountCalculator;
//# sourceMappingURL=AddonDiscountCalculator.js.map