var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/components/booking/info2/model/strategy/adapter/promotion/evaluator.ts
var evaluator_exports = {};
__export(evaluator_exports, {
  PromotionEvaluator: () => PromotionEvaluator
});
module.exports = __toCommonJS(evaluator_exports);
var import_decimal = __toESM(require("decimal.js"));
var import__ = require("../../index");
var import_index = require("./index");
var import_type = require("./type");
var defaultLocales = {
  en: {
    no_applicable_promotion: "No applicable promotion",
    promotion_not_in_time_range: "Promotion not in valid time range",
    product_not_in_promotion: "Product not in promotion scope"
  },
  "zh-CN": {
    no_applicable_promotion: "无适用的促销活动",
    promotion_not_in_time_range: "促销活动不在有效时间范围内",
    product_not_in_promotion: "商品不在促销范围内"
  },
  "zh-HK": {
    no_applicable_promotion: "無適用的促銷活動",
    promotion_not_in_time_range: "促銷活動不在有效時間範圍內",
    product_not_in_promotion: "商品不在促銷範圍內"
  }
};
var PromotionEvaluator = class {
  engine;
  adapter;
  strategyConfigs = [
    {
      metadata: {
        id: "STRATEGY_001",
        name: {
          en: "2 items for $10",
          "zh-CN": "2杯10元",
          "zh-HK": "2杯10元"
        },
        type: "promotion",
        custom: {
          display: {
            product_card: {
              text: {
                en: "2 for $10",
                "zh-CN": "2杯10元",
                "zh-HK": "2杯10元"
              },
              type: "tag"
            }
          }
        }
      },
      conditions: {
        operator: "and",
        rules: [
          {
            type: "operator",
            field: "currentDateTime",
            value: "2023-01-01 00:00:00",
            operator: ">="
          },
          {
            type: "operator",
            field: "currentDateTime",
            value: "2027-01-01 00:00:00",
            operator: "<="
          },
          {
            type: "operator",
            field: "productIdAndVariantId",
            value: [
              {
                product_id: 60736,
                product_variant_id: 0
                // 0 = 匹配任意变体
              },
              {
                product_id: 60737,
                product_variant_id: 0
                // 0 = 匹配任意变体
              }
            ],
            operator: "product_match"
          }
        ],
        actionIds: ["1"]
      },
      actions: [
        {
          id: "1",
          type: "X_ITEMS_FOR_Y_PRICE",
          value: {
            x: 2,
            // 每X件
            price: 10
            // 固定价格Y元
          },
          valueType: "object",
          target: "product",
          priority: 1,
          config: {
            allowCrossProduct: true,
            // 允许跨商品组合（A+B可以凑成一组）
            cumulative: true
            // 可累计（买5件 = 2组优惠 + 1件原价）
          }
        }
      ]
    }
  ];
  locale = "en";
  locales = defaultLocales;
  constructor() {
    this.engine = new import__.StrategyEngine({
      debug: false,
      enableTrace: false
    });
    this.adapter = new import_index.PromotionAdapter();
  }
  // ============================================
  // 配置管理
  // ============================================
  /**
   * 设置策略配置列表
   */
  setStrategyConfigs(strategyConfigs) {
    this.strategyConfigs = strategyConfigs;
  }
  /**
   * 获取策略配置列表
   */
  getStrategyConfigs() {
    return this.strategyConfigs;
  }
  /**
   * 添加策略配置
   */
  addStrategyConfig(strategyConfig) {
    this.strategyConfigs.push(strategyConfig);
  }
  /**
   * 设置语言
   */
  setLocale(locale) {
    this.locale = locale;
  }
  /**
   * 设置自定义多语言文案
   */
  setLocales(locales) {
    this.locales = { ...defaultLocales, ...locales };
  }
  /**
   * 获取多语言文案
   */
  getText(key) {
    var _a, _b;
    return ((_b = (_a = this.locales) == null ? void 0 : _a[this.locale]) == null ? void 0 : _b[key]) || key;
  }
  /**
   * 获取多语言名称
   */
  getLocalizedName(name) {
    if (typeof name === "string") {
      return name;
    }
    return name[this.locale] || name["en"] || Object.values(name)[0] || "";
  }
  // ============================================
  // 核心评估方法
  // ============================================
  /**
   * 评估商品列表
   *
   * 判断每个商品适用哪些促销活动
   *
   * @param input 评估输入
   * @returns 每个商品的促销评估结果
   */
  evaluateProducts(input) {
    const { products, strategyConfigs, channel } = input;
    const configs = strategyConfigs || this.strategyConfigs;
    const results = [];
    for (const product of products) {
      const applicablePromotions = [];
      for (const config of configs) {
        const context = this.adapter.prepareContext({
          products: [product],
          currentProduct: product,
          channel
        });
        const result = this.engine.evaluate(config, context);
        if (result.applicable && result.matchedActions.length > 0) {
          const action = result.matchedActions[0];
          const transformedResult = this.adapter.transformResult(result, {
            products: [product],
            currentProduct: product,
            channel
          });
          if (transformedResult.actionDetail) {
            applicablePromotions.push({
              strategyId: config.metadata.id,
              strategyName: config.metadata.name,
              actionType: action.type,
              actionDetail: transformedResult.actionDetail,
              display: this.getDisplayConfig(config),
              strategyConfig: config
            });
          }
        }
      }
      results.push({
        product,
        applicablePromotions,
        hasPromotion: applicablePromotions.length > 0
      });
    }
    return results;
  }
  /**
   * 评估购物车
   *
   * 返回所有适用的促销及按促销分组的商品
   *
   * @param input 评估输入
   * @returns 购物车评估结果
   */
  evaluateCart(input) {
    const { products, strategyConfigs, channel } = input;
    const configs = strategyConfigs || this.strategyConfigs;
    const productResults = this.evaluateProducts(input);
    const promotionMap = /* @__PURE__ */ new Map();
    for (const productResult of productResults) {
      for (const promo of productResult.applicablePromotions) {
        const existing = promotionMap.get(promo.strategyId);
        if (existing) {
          existing.applicableProducts.push(productResult.product);
          existing.totalQuantity += productResult.product.quantity;
          existing.totalAmount += productResult.product.price * productResult.product.quantity;
        } else {
          promotionMap.set(promo.strategyId, {
            ...promo,
            applicableProducts: [productResult.product],
            totalQuantity: productResult.product.quantity,
            totalAmount: productResult.product.price * productResult.product.quantity
          });
        }
      }
    }
    const applicablePromotions = Array.from(promotionMap.values());
    const promotionGroups = applicablePromotions.map(
      (promo) => ({
        strategyId: promo.strategyId,
        strategyName: promo.strategyName,
        actionType: promo.actionType,
        actionDetail: promo.actionDetail,
        products: promo.applicableProducts,
        totalQuantity: promo.totalQuantity,
        totalAmount: promo.totalAmount
      })
    );
    return {
      productResults,
      applicablePromotions,
      promotionGroups
    };
  }
  /**
   * 评估购物车并计算定价
   *
   * 返回处理后的商品数组（包含拆分、finalPrice）和赠品信息
   * - 对于 X_ITEMS_FOR_Y_PRICE：按原价比例均摊价格，优先使用高价商品
   * - 对于 BUY_X_GET_Y_FREE：计算赠品数量和可选赠品列表
   *
   * @param input 评估输入
   * @returns 带定价的购物车评估结果
   */
  evaluateCartWithPricing(input) {
    const { products } = input;
    const cartResult = this.evaluateCart(input);
    const sortedGroups = this.sortPromotionGroupsByPriority(
      cartResult.promotionGroups,
      cartResult.applicablePromotions
    );
    const processedQuantityMap = /* @__PURE__ */ new Map();
    const pricedProducts = [];
    const gifts = [];
    let totalOriginalAmount = new import_decimal.default(0);
    let totalFinalAmount = new import_decimal.default(0);
    for (const group of sortedGroups) {
      const { actionType, actionDetail, strategyId, strategyName } = group;
      if (actionType === import_type.PROMOTION_ACTION_TYPES.X_ITEMS_FOR_Y_PRICE) {
        const result = this.processXItemsForYPrice(
          group,
          processedQuantityMap
        );
        pricedProducts.push(...result.products);
        totalOriginalAmount = totalOriginalAmount.plus(result.originalAmount);
        totalFinalAmount = totalFinalAmount.plus(result.finalAmount);
      } else if (actionType === import_type.PROMOTION_ACTION_TYPES.BUY_X_GET_Y_FREE) {
        const result = this.processBuyXGetYFree(
          group,
          processedQuantityMap
        );
        pricedProducts.push(...result.products);
        totalOriginalAmount = totalOriginalAmount.plus(result.originalAmount);
        totalFinalAmount = totalFinalAmount.plus(result.finalAmount);
        if (result.giftInfo) {
          gifts.push(result.giftInfo);
        }
      }
    }
    const remainingProducts = this.getRemainingProducts(
      products,
      processedQuantityMap
    );
    for (const product of remainingProducts) {
      const amount = new import_decimal.default(product.price).mul(product.quantity);
      totalOriginalAmount = totalOriginalAmount.plus(amount);
      totalFinalAmount = totalFinalAmount.plus(amount);
    }
    pricedProducts.push(...remainingProducts);
    const totalDiscount = totalOriginalAmount.minus(totalFinalAmount);
    return {
      products: pricedProducts,
      gifts,
      totalDiscount: import_decimal.default.max(0, totalDiscount).toNumber()
    };
  }
  /**
   * 获取商品适用的促销列表
   *
   * 简化方法，用于商品卡片展示
   *
   * @param product 商品
   * @param strategyConfigs 策略配置（可选）
   * @returns 适用的促销列表
   */
  getProductPromotions(product, strategyConfigs) {
    var _a;
    const results = this.evaluateProducts({
      products: [product],
      strategyConfigs
    });
    return ((_a = results[0]) == null ? void 0 : _a.applicablePromotions) || [];
  }
  /**
   * 获取商品的促销标签
   *
   * 用于商品卡片展示
   *
   * @param product 商品
   * @param strategyConfigs 策略配置（可选）
   * @returns 促销标签列表
   */
  getProductPromotionTags(product, strategyConfigs) {
    const promotions = this.getProductPromotions(product, strategyConfigs);
    return promotions.filter((promo) => promo.display).map((promo) => ({
      text: this.getLocalizedName(promo.display.text),
      type: promo.display.type,
      strategyId: promo.strategyId
    }));
  }
  /**
   * 查找商品适用的策略配置
   *
   * @param product 商品
   * @param strategyConfigs 策略配置列表（可选）
   * @returns 适用的策略配置列表
   */
  findApplicableStrategies(product, strategyConfigs) {
    const configs = strategyConfigs || this.strategyConfigs;
    return configs.filter(
      (config) => this.isProductInStrategy(product, config)
    );
  }
  /**
   * 批量获取商品列表的适用策略信息
   *
   * 用于给商品列表追加策略标签信息
   * 只检查商品 ID 匹配和策略时间范围
   *
   * @param input 评估输入（商品列表）
   * @returns 每个商品的适用策略完整数据
   */
  getProductsApplicableStrategies(input) {
    const { products, strategyConfigs, channel } = input;
    const configs = strategyConfigs || this.strategyConfigs;
    const results = [];
    for (const product of products) {
      const applicableStrategies = [];
      for (const config of configs) {
        const context = this.adapter.prepareContext({
          products: [product],
          currentProduct: product,
          channel
        });
        const result = this.engine.evaluate(config, context);
        if (result.applicable && result.matchedActions.length > 0) {
          const action = result.matchedActions[0];
          const transformedResult = this.adapter.transformResult(result, {
            products: [product],
            currentProduct: product,
            channel
          });
          if (transformedResult.actionDetail) {
            applicableStrategies.push({
              strategyId: config.metadata.id,
              strategyName: config.metadata.name,
              strategyMetadata: config.metadata,
              actionType: action.type,
              actionDetail: transformedResult.actionDetail,
              display: this.getDisplayConfig(config),
              strategyConfig: config
            });
          }
        }
      }
      results.push({
        product,
        applicableStrategies,
        hasApplicableStrategy: applicableStrategies.length > 0
      });
    }
    return results;
  }
  // ============================================
  // 私有辅助方法
  // ============================================
  /**
   * 按优先级排序促销组
   * 优先级从 strategyConfig.actions[0].priority 获取，数值越小优先级越高
   */
  sortPromotionGroupsByPriority(groups, promotions) {
    var _a, _b;
    const priorityMap = /* @__PURE__ */ new Map();
    for (const promo of promotions) {
      const actions = ((_a = promo.strategyConfig) == null ? void 0 : _a.actions) || [];
      const priority = ((_b = actions[0]) == null ? void 0 : _b.priority) ?? 999;
      priorityMap.set(promo.strategyId, priority);
    }
    return [...groups].sort((a, b) => {
      const priorityA = priorityMap.get(a.strategyId) ?? 999;
      const priorityB = priorityMap.get(b.strategyId) ?? 999;
      return priorityA - priorityB;
    });
  }
  /**
   * 处理 X件Y元 促销
   *
   * 1. 展开商品为单件列表，按价格从高到低排序
   * 2. 计算可凑成的组数
   * 3. 按原价比例均摊价格
   * 4. 拆分商品（部分参与促销、部分原价）
   *
   * 注意：每个商品按 id 独立处理，不会合并不同 id 的商品
   */
  processXItemsForYPrice(group, processedQuantityMap) {
    const { strategyId, actionDetail, products: groupProducts } = group;
    const detail = actionDetail;
    const { x, price: groupPrice, cumulative } = detail;
    const result = [];
    let originalAmount = new import_decimal.default(0);
    let finalAmount = new import_decimal.default(0);
    const unitProducts = [];
    for (const product of groupProducts) {
      const key = this.getProductKey(product);
      const processedQty = processedQuantityMap.get(key) || 0;
      const availableQty = product.quantity - processedQty;
      if (availableQty <= 0) continue;
      for (let i = 0; i < availableQty; i++) {
        unitProducts.push({
          product,
          price: product.price,
          productId: product.id
        });
      }
    }
    if (unitProducts.length === 0) {
      return { products: [], originalAmount: 0, finalAmount: 0 };
    }
    unitProducts.sort((a, b) => b.price - a.price);
    const totalUnits = unitProducts.length;
    const groupCount = cumulative ? Math.floor(totalUnits / x) : totalUnits >= x ? 1 : 0;
    const promotionUnits = groupCount * x;
    const inPromotionUnits = unitProducts.slice(0, promotionUnits);
    const notInPromotionUnits = unitProducts.slice(promotionUnits);
    const promotionQtyByProductId = /* @__PURE__ */ new Map();
    for (const unit of inPromotionUnits) {
      const id = unit.productId;
      promotionQtyByProductId.set(id, (promotionQtyByProductId.get(id) || 0) + 1);
    }
    const remainingQtyByProductId = /* @__PURE__ */ new Map();
    for (const unit of notInPromotionUnits) {
      const id = unit.productId;
      remainingQtyByProductId.set(id, (remainingQtyByProductId.get(id) || 0) + 1);
    }
    const allocatedPricesByProductId = /* @__PURE__ */ new Map();
    for (let g = 0; g < groupCount; g++) {
      const startIdx = g * x;
      const endIdx = startIdx + x;
      const groupUnits = inPromotionUnits.slice(startIdx, endIdx);
      const groupOriginalTotal = groupUnits.reduce(
        (sum, u) => sum.plus(u.price),
        new import_decimal.default(0)
      );
      const groupPriceDecimal = new import_decimal.default(groupPrice);
      let allocatedSum = new import_decimal.default(0);
      for (let i = 0; i < groupUnits.length; i++) {
        const unit = groupUnits[i];
        const isLastUnit = i === groupUnits.length - 1;
        const ratio = groupOriginalTotal.eq(0) ? new import_decimal.default(0) : new import_decimal.default(unit.price).div(groupOriginalTotal);
        const allocatedDecimal = isLastUnit ? groupPriceDecimal.minus(allocatedSum) : groupPriceDecimal.mul(ratio);
        const productId = unit.productId;
        const prices = allocatedPricesByProductId.get(productId) || [];
        prices.push(allocatedDecimal);
        allocatedPricesByProductId.set(productId, prices);
        allocatedSum = allocatedSum.plus(allocatedDecimal);
      }
    }
    for (const product of groupProducts) {
      const key = this.getProductKey(product);
      const processedQty = processedQuantityMap.get(key) || 0;
      const availableQty = product.quantity - processedQty;
      if (availableQty <= 0) continue;
      const promoQty = promotionQtyByProductId.get(product.id) || 0;
      const remainingQty = remainingQtyByProductId.get(product.id) || 0;
      const allocatedPrices = allocatedPricesByProductId.get(product.id) || [];
      if (promoQty > 0 && remainingQty === 0) {
        const totalAllocated = allocatedPrices.reduce(
          (sum, p) => sum.plus(p),
          new import_decimal.default(0)
        );
        const finalPricePerUnit = this.formatPrice(totalAllocated.div(promoQty));
        result.push({
          ...product,
          quantity: promoQty,
          finalPrice: finalPricePerUnit,
          strategyId,
          inPromotion: true,
          isSplit: false
        });
        const productOriginalAmount = new import_decimal.default(product.price).mul(promoQty);
        originalAmount = originalAmount.plus(productOriginalAmount);
        finalAmount = finalAmount.plus(totalAllocated);
      } else if (promoQty === 0 && remainingQty > 0) {
        result.push({
          ...product,
          quantity: remainingQty,
          finalPrice: this.formatPrice(product.price),
          strategyId: void 0,
          inPromotion: false,
          isSplit: false
        });
        const amount = new import_decimal.default(product.price).mul(remainingQty);
        originalAmount = originalAmount.plus(amount);
        finalAmount = finalAmount.plus(amount);
      } else if (promoQty > 0 && remainingQty > 0) {
        const totalAllocated = allocatedPrices.reduce(
          (sum, p) => sum.plus(p),
          new import_decimal.default(0)
        );
        const finalPricePerUnit = this.formatPrice(totalAllocated.div(promoQty));
        result.push({
          ...product,
          id: this.generateRandomId(),
          originalId: product.id,
          quantity: promoQty,
          finalPrice: finalPricePerUnit,
          strategyId,
          inPromotion: true,
          isSplit: true
        });
        const promoOriginalAmount = new import_decimal.default(product.price).mul(promoQty);
        originalAmount = originalAmount.plus(promoOriginalAmount);
        finalAmount = finalAmount.plus(totalAllocated);
        result.push({
          ...product,
          quantity: remainingQty,
          finalPrice: this.formatPrice(product.price),
          strategyId: void 0,
          inPromotion: false,
          isSplit: true
        });
        const remainingAmount = new import_decimal.default(product.price).mul(remainingQty);
        originalAmount = originalAmount.plus(remainingAmount);
        finalAmount = finalAmount.plus(remainingAmount);
      }
      processedQuantityMap.set(key, processedQty + availableQty);
    }
    return {
      products: result,
      originalAmount: originalAmount.toNumber(),
      finalAmount: finalAmount.toNumber()
    };
  }
  /**
   * 处理 买X送Y 促销
   *
   * 计算赠品数量，商品本身价格不变
   */
  processBuyXGetYFree(group, processedQuantityMap) {
    const { strategyId, strategyName, actionDetail, products: groupProducts } = group;
    const detail = actionDetail;
    const { buyQuantity, freeQuantity, cumulative, giftProducts } = detail;
    const result = [];
    let originalAmount = new import_decimal.default(0);
    let finalAmount = new import_decimal.default(0);
    let totalAvailableQty = 0;
    for (const product of groupProducts) {
      const key = this.getProductKey(product);
      const processedQty = processedQuantityMap.get(key) || 0;
      const availableQty = product.quantity - processedQty;
      if (availableQty <= 0) continue;
      totalAvailableQty += availableQty;
      result.push({
        ...product,
        quantity: availableQty,
        finalPrice: this.formatPrice(product.price),
        strategyId,
        inPromotion: true,
        isSplit: availableQty < product.quantity
      });
      const amount = new import_decimal.default(product.price).mul(availableQty);
      originalAmount = originalAmount.plus(amount);
      finalAmount = finalAmount.plus(amount);
      processedQuantityMap.set(key, processedQty + availableQty);
    }
    let giftCount = 0;
    if (totalAvailableQty >= buyQuantity) {
      giftCount = cumulative ? Math.floor(totalAvailableQty / buyQuantity) * freeQuantity : freeQuantity;
    }
    const giftInfo = giftCount > 0 ? {
      strategyId,
      strategyName,
      giftCount,
      giftOptions: giftProducts || []
    } : null;
    return {
      products: result,
      originalAmount: originalAmount.toNumber(),
      finalAmount: finalAmount.toNumber(),
      giftInfo
    };
  }
  /**
   * 获取未参与任何促销的商品
   */
  getRemainingProducts(allProducts, processedQuantityMap) {
    const result = [];
    for (const product of allProducts) {
      const key = this.getProductKey(product);
      const processedQty = processedQuantityMap.get(key) || 0;
      const remainingQty = product.quantity - processedQty;
      if (remainingQty > 0) {
        result.push({
          ...product,
          quantity: remainingQty,
          finalPrice: this.formatPrice(product.price),
          strategyId: void 0,
          inPromotion: false,
          isSplit: remainingQty < product.quantity
        });
      }
    }
    return result;
  }
  /**
   * 价格统一保留两位小数
   */
  formatPrice(value) {
    return new import_decimal.default(value).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber();
  }
  /**
   * 获取商品唯一标识 key
   * 使用商品的 id 作为唯一标识，不同 id 的商品不会被合并
   */
  getProductKey(product) {
    return String(product.id);
  }
  /**
   * 生成随机ID
   */
  generateRandomId() {
    return Math.floor(Math.random() * 1e9) + Date.now();
  }
  /**
   * 检查商品是否在策略的适用范围内
   */
  isProductInStrategy(product, config) {
    const productMatchRule = this.findProductMatchRule(config);
    if (!productMatchRule) {
      return true;
    }
    const configProducts = productMatchRule.value;
    return this.isProductMatch(product, configProducts);
  }
  /**
   * 查找商品匹配规则
   */
  findProductMatchRule(config) {
    var _a;
    if (!((_a = config == null ? void 0 : config.conditions) == null ? void 0 : _a.rules)) {
      return null;
    }
    return config.conditions.rules.find(
      (rule) => rule.field === "productIdAndVariantId" && (rule.operator === "product_match" || rule.operator === "object_in")
    );
  }
  /**
   * 检查商品是否匹配配置
   */
  isProductMatch(product, configProducts) {
    return configProducts.some((config) => {
      if (config.product_id !== product.product_id) {
        return false;
      }
      if (config.product_variant_id === 0) {
        return true;
      }
      return config.product_variant_id === product.product_variant_id;
    });
  }
  /**
   * 获取展示配置
   */
  getDisplayConfig(config) {
    var _a;
    const custom = config.metadata.custom;
    if ((_a = custom == null ? void 0 : custom.display) == null ? void 0 : _a.product_card) {
      return {
        text: custom.display.product_card.text,
        type: custom.display.product_card.type
      };
    }
    return void 0;
  }
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  PromotionEvaluator
});
