function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
import dayjs from 'dayjs';
import Decimal from 'decimal.js';
import { composeLinePrice, createUuidV4, ensureProductSku, getBundleSellingMagnitude, getProductSkuOptions, normalizeProductSkuOptions, resolveManualOverrideLineOriginalPrice, sumOptionUnitPrice } from "../../modules/Order/utils";
import { ensureManualProductDiscountList } from "../../modules/Order/utils/manualProductDiscount";

/**
 * 构建金额全为 0 的空 summary。
 * 作为尚未计算金额时的兜底默认值，避免下游因 undefined 报错。
 */
export function createEmptySummary() {
  return {
    product_quantity: 0,
    product_original_amount: '0.00',
    product_amount: '0.00',
    product_expect_amount: '0.00',
    product_tax_fee: '0.00',
    shipping_fee: '0.00',
    shipping_tax_fee: '0.00',
    tax_fee: '0.00',
    surcharge_fee: '0.00',
    surcharges: [],
    discount_amount: '0.00',
    deposit_amount: '0.00',
    expect_amount: '0.00',
    total_amount: '0.00',
    total_refund_amount: '0.00',
    customer_paid_amount: '0.00',
    order_paid_amount: '0.00',
    amount_gap: '0.00',
    rounding_amount: '0.00',
    pay_service_charge_amount: '0.00'
  };
}

/**
 * 商品数量安全取值。
 * - NaN / undefined / < 1 均视作 1（最低起订量）
 * - 有值时取整（不支持小数数量）
 */
export function getSafeProductNum(num) {
  if (!num || Number.isNaN(num)) return 1;
  if (num < 1) return 1;
  return Math.floor(num);
}

/**
 * 宽松布尔值转换。
 * 兼容后端/配置中心常见的 boolean / number / string 表达，统一归一成 true/false。
 */
export function toBoolean(value) {
  if (typeof value === 'boolean') return value;
  if (typeof value === 'number') return value !== 0;
  if (typeof value === 'string') {
    var normalized = value.trim().toLowerCase();
    return ['1', 'true', 'yes', 'y', 'on'].includes(normalized);
  }
  return false;
}

/**
 * 将值归一化为有效的正向字符串。
 * null / undefined / 空串 / '0' / 'null' 统一视为无效值并返回 undefined。
 */
export function toPositiveString(value) {
  if (value === null || value === undefined || value === '') return undefined;
  var normalized = String(value).trim();
  if (!normalized || normalized === '0' || normalized.toLowerCase() === 'null') {
    return undefined;
  }
  return normalized;
}

/**
 * 归一化 item rule 策略模型 ID 列表。
 * - 支持 string / number 混合输入
 * - 仅保留 > 0 的合法数字
 * - 自动去重
 */
export function normalizeEnabledItemRuleIds(rawIds) {
  if (!Array.isArray(rawIds)) return [];
  var uniqueIds = new Set();
  var _iterator = _createForOfIteratorHelper(rawIds),
    _step;
  try {
    for (_iterator.s(); !(_step = _iterator.n()).done;) {
      var item = _step.value;
      var strategyId = Number(item);
      if (Number.isFinite(strategyId) && strategyId > 0) {
        uniqueIds.add(strategyId);
      }
    }
  } catch (err) {
    _iterator.e(err);
  } finally {
    _iterator.f();
  }
  return Array.from(uniqueIds);
}

/**
 * 从 tableConfig 中提取合法策略模型 ID 列表。
 */
export function extractStrategyModelIdsFromTableConfig(tableConfig) {
  var rawIds = Array.isArray(tableConfig === null || tableConfig === void 0 ? void 0 : tableConfig.strategy_model_ids) ? tableConfig.strategy_model_ids : [];
  return rawIds.map(function (id) {
    return Number(id);
  }).filter(function (id) {
    return Number.isFinite(id) && id > 0;
  });
}

/**
 * 仅保留 item_rule 类型策略。
 */
export function normalizeItemRuleStrategies(configs) {
  if (!Array.isArray(configs)) return [];
  return configs.filter(function (config) {
    var _metadata;
    return Boolean(config && _typeof(config) === 'object' && (config === null || config === void 0 || (_metadata = config.metadata) === null || _metadata === void 0 ? void 0 : _metadata.type) === 'item_rule');
  });
}
export function toNonNegativeNumber(value) {
  if (typeof value === 'number') {
    return Number.isFinite(value) && value >= 0 ? value : 0;
  }
  if (typeof value === 'string') {
    var parsed = Number(value);
    return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
  }
  return 0;
}
export function toNonNegativeInt(value) {
  return Math.floor(toNonNegativeNumber(value));
}
export function toPriceString(value) {
  var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '0.00';
  var parsedValue = Number(value);
  if (Number.isNaN(parsedValue)) return fallback;
  return parsedValue.toFixed(2);
}
export function buildProductKey(productId, productVariantId) {
  return "".concat(productId, "_").concat(productVariantId);
}
export function getTopLevelProductId(product) {
  var _product$product_id;
  var rawProductId = (_product$product_id = product.product_id) !== null && _product$product_id !== void 0 ? _product$product_id : product.id;
  var productId = Number(rawProductId);
  if (!Number.isFinite(productId) || productId <= 0) return null;
  return productId;
}
export function getTopLevelVariantId(product) {
  var _product$product_vari;
  var rawVariantId = (_product$product_vari = product.product_variant_id) !== null && _product$product_vari !== void 0 ? _product$product_vari : product.variant_id;
  if (rawVariantId === undefined || rawVariantId === null || rawVariantId === '') {
    return null;
  }
  var variantId = Number(rawVariantId);
  if (!Number.isFinite(variantId) || variantId <= 0) return null;
  return variantId;
}
export function buildQuantityLimitIndex(limits) {
  var exactLimitMap = new Map();
  var productLimitMap = new Map();
  var _iterator2 = _createForOfIteratorHelper(limits),
    _step2;
  try {
    for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
      var limit = _step2.value;
      var targets = limit.targets || [];
      // 多目标规则（OR 组）只做购物车聚合校验，不下发到单品维度，
      // 避免 UI 把「组内至少 1 份」误当作每款商品各自的 min，锁死减号按钮。
      if (targets.length !== 1) continue;
      var target = targets[0];
      var productId = Number(target.product_id);
      if (!Number.isFinite(productId) || productId <= 0) continue;
      var variantId = Number(target.product_variant_id);
      var hasVariant = Number.isFinite(variantId) && variantId > 0;
      if (hasVariant) {
        var exactKey = buildProductKey(productId, variantId);
        var existed = exactLimitMap.get(exactKey) || [];
        exactLimitMap.set(exactKey, [].concat(_toConsumableArray(existed), [limit]));
      } else {
        var _existed = productLimitMap.get(productId) || [];
        productLimitMap.set(productId, [].concat(_toConsumableArray(_existed), [limit]));
      }
    }
  } catch (err) {
    _iterator2.e(err);
  } finally {
    _iterator2.f();
  }
  return {
    exactLimitMap: exactLimitMap,
    productLimitMap: productLimitMap
  };
}
export function resolveSkuMatchedQuantityLimits(params) {
  var productId = params.productId,
    variantId = params.variantId,
    limitIndex = params.limitIndex;
  var exactMatched = variantId && variantId > 0 ? limitIndex.exactLimitMap.get(buildProductKey(productId, variantId)) || [] : [];
  var productMatched = limitIndex.productLimitMap.get(productId) || [];
  return [].concat(_toConsumableArray(exactMatched), _toConsumableArray(productMatched));
}
export function aggregateItemRuleLimit(matchedLimits) {
  if (!matchedLimits.length) return null;
  var min;
  var max;
  var remainingMax;
  var exact;
  var mustInclude = false;

  // 聚合 validationMessage 按 min / max 两个方向分别输出：
  //   - maxValidationMessage：触发"当前 max / remainingMax / exact"的那条规则的文案
  //   - minValidationMessage：触发"当前 min / exact"的那条规则的文案
  // 各自再回退到其他带文案的规则（最后回退到第一条非空 validationMessage）。
  // 前端可根据"加号/减号被拦"的方向取对应文案。
  var maxSourceLimit;
  var remainingMaxSourceLimit;
  var exactSourceLimit;
  var minSourceLimit;
  var firstMessagedLimit;
  var _iterator3 = _createForOfIteratorHelper(matchedLimits),
    _step3;
  try {
    for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
      var limit = _step3.value;
      if (typeof limit.requiredMin === 'number' && Number.isFinite(limit.requiredMin)) {
        if (min === undefined || limit.requiredMin > min) {
          min = limit.requiredMin;
          minSourceLimit = limit;
        }
      }
      if (typeof limit.requiredMax === 'number' && Number.isFinite(limit.requiredMax)) {
        if (max === undefined || limit.requiredMax < max) {
          max = limit.requiredMax;
          maxSourceLimit = limit;
        }
      }
      if (typeof limit.remainingMax === 'number' && Number.isFinite(limit.remainingMax)) {
        if (remainingMax === undefined || limit.remainingMax < remainingMax) {
          remainingMax = limit.remainingMax;
          remainingMaxSourceLimit = limit;
        }
      }
      if (typeof limit.requiredExact === 'number' && Number.isFinite(limit.requiredExact)) {
        exact = limit.requiredExact;
        exactSourceLimit = limit;
      }
      mustInclude = mustInclude || Boolean(limit.mustInclude);
      if (!firstMessagedLimit && limit.validationMessage) {
        firstMessagedLimit = limit;
      }
    }
  } catch (err) {
    _iterator3.e(err);
  } finally {
    _iterator3.f();
  }
  if (typeof exact === 'number' && Number.isFinite(exact)) {
    min = exact;
    max = exact;
  }
  var maxMessageSource = maxSourceLimit || remainingMaxSourceLimit || exactSourceLimit || firstMessagedLimit;
  var minMessageSource = minSourceLimit || exactSourceLimit || firstMessagedLimit;
  var maxValidationMessage = maxMessageSource === null || maxMessageSource === void 0 ? void 0 : maxMessageSource.validationMessage;
  var rawMaxValidationMessage = maxMessageSource === null || maxMessageSource === void 0 ? void 0 : maxMessageSource.rawValidationMessage;
  var minValidationMessage = minMessageSource === null || minMessageSource === void 0 ? void 0 : minMessageSource.validationMessage;
  var rawMinValidationMessage = minMessageSource === null || minMessageSource === void 0 ? void 0 : minMessageSource.rawValidationMessage;

  // validationMessage / rawValidationMessage 保留为"最严格限制"的聚合文案，
  // 便于旧消费者（只关心 max 侧）不破坏。优先 max → min。
  var validationMessage = maxValidationMessage !== null && maxValidationMessage !== void 0 ? maxValidationMessage : minValidationMessage;
  var rawValidationMessage = rawMaxValidationMessage !== null && rawMaxValidationMessage !== void 0 ? rawMaxValidationMessage : rawMinValidationMessage;
  return {
    min: min,
    max: max,
    remainingMax: remainingMax,
    exact: exact,
    mustInclude: mustInclude,
    validationMessage: validationMessage,
    rawValidationMessage: rawValidationMessage,
    maxValidationMessage: maxValidationMessage,
    rawMaxValidationMessage: rawMaxValidationMessage,
    minValidationMessage: minValidationMessage,
    rawMinValidationMessage: rawMinValidationMessage
  };
}
export function buildItemRuleBusinessData(params) {
  var tempOrder = params.tempOrder,
    runtimeConfig = params.runtimeConfig,
    itemRuleConfigs = params.itemRuleConfigs;
  var rawPax = runtimeConfig.pax || {};
  var adultPax = toNonNegativeInt(rawPax.adult);
  var childPax = toNonNegativeInt(rawPax.child);
  var totalPax = toNonNegativeInt(rawPax.total) || adultPax + childPax || 1;
  var cartItems = tempOrder.products.reduce(function (result, product) {
    if (typeof product.product_id !== 'number') return result;
    result.push(_objectSpread({
      product_id: product.product_id,
      quantity: toNonNegativeInt(product.num)
    }, typeof product.product_variant_id === 'number' ? {
      product_variant_id: product.product_variant_id
    } : {}));
    return result;
  }, []);
  var historicalItems = Array.isArray(runtimeConfig.historicalItems) ? runtimeConfig.historicalItems.reduce(function (result, item) {
    if (typeof (item === null || item === void 0 ? void 0 : item.product_id) !== 'number') return result;
    result.push(_objectSpread({
      product_id: item.product_id,
      quantity: toNonNegativeInt(item.quantity)
    }, typeof item.product_variant_id === 'number' ? {
      product_variant_id: item.product_variant_id
    } : {}));
    return result;
  }, []) : [];
  return {
    pax: {
      total: totalPax,
      adult: adultPax,
      child: childPax
    },
    cartItems: cartItems,
    historicalItems: historicalItems,
    serviceType: runtimeConfig.serviceType || 'dine-in',
    submissionIndex: typeof runtimeConfig.submissionIndex === 'number' ? toNonNegativeInt(runtimeConfig.submissionIndex) : tempOrder.order_id ? 1 : 0,
    custom: runtimeConfig.custom || {},
    strategyConfigs: itemRuleConfigs
  };
}
export function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
  if (!Array.isArray(productList)) return productList;
  var limitIndex = buildQuantityLimitIndex(limits || []);
  var _iterator4 = _createForOfIteratorHelper(productList),
    _step4;
  try {
    for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
      var item = _step4.value;
      if (!item || _typeof(item) !== 'object') continue;
      var productItem = item;
      var productId = getTopLevelProductId(productItem);
      if (productId === null) continue;
      var variantId = getTopLevelVariantId(productItem);
      var matchedLimits = limits.length ? resolveSkuMatchedQuantityLimits({
        productId: productId,
        variantId: variantId,
        limitIndex: limitIndex
      }) : [];
      var aggregatedLimit = aggregateItemRuleLimit(matchedLimits);
      if (aggregatedLimit) {
        productItem.item_rule_limit = aggregatedLimit;
      } else if ('item_rule_limit' in productItem) {
        delete productItem.item_rule_limit;
      }
    }
  } catch (err) {
    _iterator4.e(err);
  } finally {
    _iterator4.f();
  }
  return productList;
}

/**
 * 将选项行 / 套餐行归一成稳定 JSON，用于「同 SKU 是否合并」判断。
 * 数组元素先按主键排序再序列化，避免顺序差异导致误判为不同行。
 */
export function buildProductLineFingerprint(productOptionItem, productBundle) {
  var optArr = Array.isArray(productOptionItem) ? productOptionItem : [];
  var normalizedOpts = optArr.map(function (item) {
    var _ref, _item$add_price;
    return {
      option_group_item_id: Number(item === null || item === void 0 ? void 0 : item.option_group_item_id) || 0,
      option_group_id: Number(item === null || item === void 0 ? void 0 : item.option_group_id) || 0,
      num: typeof (item === null || item === void 0 ? void 0 : item.num) === 'number' && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
      price: String((_ref = (_item$add_price = item === null || item === void 0 ? void 0 : item.add_price) !== null && _item$add_price !== void 0 ? _item$add_price : item === null || item === void 0 ? void 0 : item.price) !== null && _ref !== void 0 ? _ref : '')
    };
  }).sort(function (p, q) {
    if (p.option_group_item_id !== q.option_group_item_id) {
      return p.option_group_item_id - q.option_group_item_id;
    }
    if (p.option_group_id !== q.option_group_id) return p.option_group_id - q.option_group_id;
    if (p.num !== q.num) return p.num - q.num;
    return p.price.localeCompare(q.price);
  });
  var bundleArr = Array.isArray(productBundle) ? productBundle : [];
  var normalizedBundles = bundleArr.map(function (item) {
    var _ref2, _item$bundle_id;
    return {
      bundle_id: Number((_ref2 = (_item$bundle_id = item === null || item === void 0 ? void 0 : item.bundle_id) !== null && _item$bundle_id !== void 0 ? _item$bundle_id : item === null || item === void 0 ? void 0 : item.id) !== null && _ref2 !== void 0 ? _ref2 : 0) || 0,
      product_id: Number(item === null || item === void 0 ? void 0 : item.product_id) || 0,
      num: typeof (item === null || item === void 0 ? void 0 : item.num) === 'number' && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1
    };
  }).sort(function (p, q) {
    if (p.bundle_id !== q.bundle_id) return p.bundle_id - q.bundle_id;
    if (p.product_id !== q.product_id) return p.product_id - q.product_id;
    return p.num - q.num;
  });
  return JSON.stringify([normalizedOpts, normalizedBundles]);
}

/**
 * removeProductFromOrder 仅传 SKU 时的通配 identity（对象上未声明选项键）。
 * 与显式 `product_sku: { option: [] }` 区分：后者只匹配「无选项」行。
 */
export function isSkuOnlyDeleteIdentity(x) {
  if (x.unique_identification_number || x.identity_key) return false;
  return !('product_sku' in x) && !('product_bundle' in x);
}
function fingerprintForIdentityWithOptionKeys(x) {
  var row = x;
  var opts = 'product_sku' in row ? getProductSkuOptions(row) : [];
  var buds = 'product_bundle' in row ? Array.isArray(row.product_bundle) ? row.product_bundle : [] : [];
  return buildProductLineFingerprint(opts, buds);
}

/**
 * 判断两个商品 identity 是否匹配（不透明 identity 契约）。
 *
 * 调用约定：始终 `isIdentityMatch(line, callerIdentity)`。
 * - 若 SKU（product_id + product_variant_id）不一致 → 不匹配。
 * - **双方都带** `identity_key` → 严格字符串相等比较（不再猜测合成 key / metadata 桥接）。
 *   这是 opaque identity 契约的标准路径：UI 删改时透传 SDK 回灌的 identity_key。
 * - 否则（即至少一侧未声明 identity_key）→ 进入「SKU 通配 / 显式空选项 / 指纹」回退路径，
 *   忽略线侧 identity_key，按内容语义匹配。这给「行已 opaque、调用方却想按 SKU 通配 / 选项指纹删除」留兼容入口。
 */
export function isIdentityMatch(a, b) {
  var _ref3, _metadata$unique_iden, _metadata2, _ref4, _metadata$unique_iden2, _metadata3;
  if (a.product_id !== b.product_id || a.product_variant_id !== b.product_variant_id) return false;
  var aUid = (_ref3 = (_metadata$unique_iden = (_metadata2 = a.metadata) === null || _metadata2 === void 0 ? void 0 : _metadata2.unique_identification_number) !== null && _metadata$unique_iden !== void 0 ? _metadata$unique_iden : a.unique_identification_number) !== null && _ref3 !== void 0 ? _ref3 : a.identity_key;
  var bUid = (_ref4 = (_metadata$unique_iden2 = (_metadata3 = b.metadata) === null || _metadata3 === void 0 ? void 0 : _metadata3.unique_identification_number) !== null && _metadata$unique_iden2 !== void 0 ? _metadata$unique_iden2 : b.unique_identification_number) !== null && _ref4 !== void 0 ? _ref4 : b.identity_key;
  var aHasKey = typeof aUid === 'string' && aUid.length > 0;
  var bHasKey = typeof bUid === 'string' && bUid.length > 0;
  if (aHasKey && bHasKey) return aUid === bUid;
  if (isSkuOnlyDeleteIdentity(a) || isSkuOnlyDeleteIdentity(b)) return true;
  return fingerprintForIdentityWithOptionKeys(a) === fingerprintForIdentityWithOptionKeys(b);
}

/**
 * 根据 identity 在商品列表中定位下标。
 * 用于判断商品是否已存在（已存在则累加数量，否则新增）。
 */
export function getProductIdentityIndex(products, identity) {
  return products.findIndex(function (item) {
    return isIdentityMatch(item, identity);
  });
}

/**
 * 对外部传入的商品对象做归一化（v2 composite 语义）：
 * - 补全可选字段默认值（未传则使用兜底值，避免后续计算时因 undefined 导致异常）
 * - 对 num 调用 getSafeProductNum 做安全处理
 * - 保留 _origin 供后续业务流程（如促销规则）使用
 *
 * 价格字段语义（metadata 权威源 + composite 派生）：
 * - `metadata.source_product_price`：主商品/variant 基础价（已应用报价单），**不含 option**、
 *   **不含折扣**。是推导 main_product_* 的起点。variant 分支优先读 `metadata.origin.variant[vid].price`。
 * - `metadata.main_product_original_price`：`source + Σ(option.price × option.num)`，**含 option**、
 *   **不含折扣**。
 * - `metadata.main_product_selling_price`：`main_product_original_price - 主商品券 per-unit amount`，
 *   **含 option**、**含折扣**。
 * - 行级 `selling_price` = `main_product_selling_price + Σ(bundle_selling_price × num)`。
 * - 行级 `original_price` = `main_product_original_price + Σ(bundle 原价 × num)`。
 *
 * 迁移与幂等：
 * - `metadata.price_schema_version === 2` → 已新语义归一化，保留 main_product_* 原值（保留折扣）。
 * - 其它情况（v1 / 缺字段 / 无 metadata）→ 按"main_product_selling_price 曾是 main-only"的旧约定
 *   反推 legacyDiscount，再以新 source + options 基准重算。最终统一打上 `price_schema_version: 2`。
 * - 因此多次 normalize 不会重复叠加 option/bundle。
 */
export function normalizeOrderProduct(product) {
  var _product$metadata, _metadata$origin, _product$product_sku, _metadata$origin2, _variantList$find, _product$is_charge_ta;
  var metadata = _objectSpread({}, product.metadata || {});
  // 不透明 identity 契约：每条订单行必须带 identity_key。
  // 调用方未传时由 SDK 自动生成 UUID，后续 update/remove 只做严格比对，避免猜测合成 key。
  var resolvedIdentityKey = (_product$metadata = product.metadata) !== null && _product$metadata !== void 0 && _product$metadata.unique_identification_number ? String(product.metadata.unique_identification_number) : product.unique_identification_number && String(product.unique_identification_number).length > 0 ? String(product.unique_identification_number) : product.identity_key && String(product.identity_key).length > 0 ? String(product.identity_key) : createUuidV4();
  metadata.unique_identification_number = resolvedIdentityKey;
  var priceOverride = metadata.price_override;
  var originOtherBundle = (_metadata$origin = metadata.origin) === null || _metadata$origin === void 0 || (_metadata$origin = _metadata$origin._extend) === null || _metadata$origin === void 0 || (_metadata$origin = _metadata$origin.other) === null || _metadata$origin === void 0 ? void 0 : _metadata$origin.bundle;
  var bundleInput = product.product_bundle || [];
  if (priceOverride !== undefined && priceOverride !== null && priceOverride !== '' && Array.isArray(originOtherBundle) && originOtherBundle.length > 0) {
    var priceById = new Map();
    originOtherBundle.forEach(function (item) {
      var _item$price;
      if ((item === null || item === void 0 ? void 0 : item.id) == null) return;
      var unit = (_item$price = item.price) !== null && _item$price !== void 0 ? _item$price : item.bundle_selling_price;
      if (unit === undefined || unit === null) return;
      priceById.set(String(item.id), String(unit));
    });
    var base = Array.isArray(bundleInput) && bundleInput.length > 0 ? bundleInput : originOtherBundle;
    bundleInput = base.map(function (item) {
      var unit = priceById.get(String(item === null || item === void 0 ? void 0 : item.id));
      if (unit === undefined) return item;
      return _objectSpread(_objectSpread({}, item), {}, {
        price: unit,
        bundle_selling_price: unit
      });
    });
  }
  var normalizedBundle = bundleInput.map(function (item) {
    var _item$price2, _item$bundle_id2, _item$bundle_product_, _item$bundle_group_id, _ref5, _ref6, _item$price3, _ref7, _item$price_type, _ref8, _item$price_type_ext;
    var magnitudeSource = _objectSpread(_objectSpread({}, item), {}, {
      // 计算 markdown 净额时，只把真实毛价交给 helper；若只有 bundle_selling_price，
      // helper 会按历史净额兜底，避免 option 二次扣减。
      price: (_item$price2 = item.price) !== null && _item$price2 !== void 0 ? _item$price2 : item.custom_price
    });
    var normalizedItem = _objectSpread(_objectSpread({}, item), {}, {
      bundle_id: (_item$bundle_id2 = item.bundle_id) !== null && _item$bundle_id2 !== void 0 ? _item$bundle_id2 : item.id,
      bundle_product_id: (_item$bundle_product_ = item.bundle_product_id) !== null && _item$bundle_product_ !== void 0 ? _item$bundle_product_ : item._bundle_product_id,
      bundle_group_id: (_item$bundle_group_id = item.bundle_group_id) !== null && _item$bundle_group_id !== void 0 ? _item$bundle_group_id : item.group_id,
      // price 保留毛价（markdown 仍为 5），由 price_type 决定符号。
      price: (_ref5 = (_ref6 = (_item$price3 = item.price) !== null && _item$price3 !== void 0 ? _item$price3 : item.custom_price) !== null && _ref6 !== void 0 ? _ref6 : item.bundle_selling_price) !== null && _ref5 !== void 0 ? _ref5 : '0.00',
      price_type: (_ref7 = (_item$price_type = item.price_type) !== null && _item$price_type !== void 0 ? _item$price_type : item.custom_price_type) !== null && _ref7 !== void 0 ? _ref7 : '',
      price_type_ext: (_ref8 = (_item$price_type_ext = item.price_type_ext) !== null && _item$price_type_ext !== void 0 ? _item$price_type_ext : item.custom_price_type_ext) !== null && _ref8 !== void 0 ? _ref8 : ''
    });
    // bundle_selling_price 落「正净额」：markdown = |price| − Σoptions；markup/原价维持原值。
    normalizedItem.bundle_selling_price = getBundleSellingMagnitude(magnitudeSource).toFixed(2);
    if (normalizedItem.price_type === 'markdown' && (normalizedItem.price_type_ext === '' || normalizedItem.price_type_ext === undefined || normalizedItem.price_type_ext === null)) {
      var _normalizedItem$custo;
      normalizedItem.custom_price = (_normalizedItem$custo = normalizedItem.custom_price) !== null && _normalizedItem$custo !== void 0 ? _normalizedItem$custo : normalizedItem.price;
      normalizedItem.price = normalizedItem.bundle_selling_price;
    }
    if ((normalizedItem.price_type === 'markdown' || normalizedItem.price_type === 'markup') && (normalizedItem.price_type_ext === '' || normalizedItem.price_type_ext === undefined || normalizedItem.price_type_ext === null)) {
      delete normalizedItem.original_total;
    }
    return normalizedItem;
  });
  var normalizedOptions = normalizeProductSkuOptions((_product$product_sku = product.product_sku) === null || _product$product_sku === void 0 ? void 0 : _product$product_sku.option);
  var optionSum = sumOptionUnitPrice(normalizedOptions);
  var productSku = _objectSpread(_objectSpread({}, ensureProductSku(product)), {}, {
    option: normalizedOptions
  });

  // 1) 解析 source_product_price。
  // 优先级：
  //   1) metadata.source_product_price（v2 权威）
  //   2) variantPrice（命中 variant_id，从 metadata.origin.variant[vid].price 读）
  //   3) _origin.price / _origin.base_price（后端语义的基础价）
  //   4) v1 兼容：无 v2 标记但存在 metadata.main_product_original_price（v1 main-only，即旧 source）
  //   5) 入参 original_price（v1 addProduct 约定：original_price 为 pre-discount 基础价）
  //   6) 入参 selling_price（最末兜底，新添加路径 caller 只给 selling_price）
  var isV2 = metadata.price_schema_version === 2 || metadata.price_schema_version === '2';
  var variantId = Number(product.product_variant_id || 0);
  var variantList = variantId ? metadata === null || metadata === void 0 || (_metadata$origin2 = metadata.origin) === null || _metadata$origin2 === void 0 ? void 0 : _metadata$origin2.variant : null;
  var variantPrice = Array.isArray(variantList) ? (_variantList$find = variantList.find(function (v) {
    return Number(v === null || v === void 0 ? void 0 : v.id) === variantId;
  })) === null || _variantList$find === void 0 ? void 0 : _variantList$find.price : undefined;
  var resolvedSource = function (_product$_origin, _product$_origin2, _ref9, _product$original_pri) {
    if (metadata.source_product_price !== undefined) {
      return String(metadata.source_product_price);
    }
    if (variantPrice !== undefined && variantPrice !== null) {
      return String(variantPrice);
    }
    var originPrice = (_product$_origin = product._origin) === null || _product$_origin === void 0 ? void 0 : _product$_origin.price;
    if (originPrice !== undefined && originPrice !== null) {
      return String(originPrice);
    }
    var originBasePrice = (_product$_origin2 = product._origin) === null || _product$_origin2 === void 0 ? void 0 : _product$_origin2.base_price;
    if (originBasePrice !== undefined && originBasePrice !== null) {
      return String(originBasePrice);
    }
    if (!isV2 && metadata.main_product_original_price !== undefined) {
      return String(metadata.main_product_original_price);
    }
    return (_ref9 = (_product$original_pri = product.original_price) !== null && _product$original_pri !== void 0 ? _product$original_pri : product.selling_price) !== null && _ref9 !== void 0 ? _ref9 : '0.00';
  }();

  // 2) 派生 main_product_original_price（含 option、不含折扣）
  var mainOriginalDec = new Decimal(Number(resolvedSource) || 0).plus(optionSum);
  var mainOriginalStr = mainOriginalDec.toDecimalPlaces(2).toFixed(2);

  // 3) 派生 main_product_selling_price（含 option、含主商品折扣）
  //    - v2 数据：直接沿用 metadata.main_product_selling_price（保留折扣）
  //    - v1 metadata：main_product_selling_price 旧语义是 main-only（≈ source-level 折后价），
  //      反推 legacyDiscount = main_original(旧) - main_selling(旧)，再用新 main_original - legacyDiscount
  //    - v1 addProduct 入参：top-level selling_price < original_price 表示主商品折扣；
  //      用差额作为 legacyDiscount 映射到新 main_selling
  //    - 其它：视为无折扣，main_selling = main_original
  var mainSellingDec;
  if (isV2 && metadata.main_product_selling_price != null) {
    mainSellingDec = new Decimal(Number(metadata.main_product_selling_price) || 0);
  } else if (metadata.main_product_selling_price != null && metadata.main_product_original_price != null) {
    var legacyOriginal = new Decimal(Number(metadata.main_product_original_price) || 0);
    var legacySelling = new Decimal(Number(metadata.main_product_selling_price) || 0);
    var legacyDiscount = legacyOriginal.minus(legacySelling);
    mainSellingDec = mainOriginalDec.minus(legacyDiscount);
  } else if (product.original_price != null && product.selling_price != null && new Decimal(Number(product.original_price) || 0).greaterThan(new Decimal(Number(product.selling_price) || 0))) {
    var topOriginal = new Decimal(Number(product.original_price) || 0);
    var topSelling = new Decimal(Number(product.selling_price) || 0);
    var _legacyDiscount = topOriginal.minus(topSelling);
    mainSellingDec = mainOriginalDec.minus(_legacyDiscount);
  } else {
    mainSellingDec = mainOriginalDec;
  }
  var mainSellingStr = mainSellingDec.toDecimalPlaces(2).toFixed(2);

  // 4) 落盘 metadata：三字段 + schema 版本 sentinel
  metadata.source_product_price = resolvedSource;
  metadata.main_product_original_price = mainOriginalStr;
  metadata.main_product_selling_price = mainSellingStr;
  metadata.price_schema_version = 2;

  // 5) 合成行级 composite（main 已含 option，本步只叠 bundle）
  var composedSellingPrice = composeLinePrice({
    mainPrice: mainSellingStr,
    bundle: normalizedBundle
  });
  var composedOriginalPrice = composeLinePrice({
    mainPrice: mainOriginalStr,
    bundle: normalizedBundle,
    useOriginalBundle: true
  });
  var finalOriginalPrice = resolveManualOverrideLineOriginalPrice({
    num: product.num,
    metadata: metadata,
    lineOriginalPrice: product.original_price
  }, composedOriginalPrice);
  var hasManualProductDiscount = (product.discount_list || []).some(function (item) {
    return (item === null || item === void 0 ? void 0 : item.type) === 'product';
  });
  var manualOriginalPrice = hasManualProductDiscount && product.original_price != null ? String(product.original_price) : finalOriginalPrice;
  var discountList = ensureManualProductDiscountList({
    discountList: product.discount_list,
    metadata: metadata,
    originalPrice: manualOriginalPrice,
    sellingPrice: composedSellingPrice,
    quantity: getSafeProductNum(product.num)
  });
  return {
    order_detail_id: product.order_detail_id || null,
    product_id: product.product_id,
    num: getSafeProductNum(product.num),
    product_variant_id: product.product_variant_id,
    product_sku: productSku,
    selling_price: composedSellingPrice,
    original_price: manualOriginalPrice,
    tax_fee: product.tax_fee || '0.00',
    is_charge_tax: (_product$is_charge_ta = product.is_charge_tax) !== null && _product$is_charge_ta !== void 0 ? _product$is_charge_ta : 0,
    discount_list: discountList,
    product_bundle: normalizedBundle,
    metadata: metadata,
    note: product.note != null ? String(product.note) : ''
  };
}

/**
 * 从 reservation.enabled_reservation_rules 中收集 type=link 的商品 id。
 */
export function collectLinkProductIdsFromReservationRules(rules) {
  if (!Array.isArray(rules)) return [];
  var ids = [];
  var _iterator5 = _createForOfIteratorHelper(rules),
    _step5;
  try {
    for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
      var entry = _step5.value;
      if (!entry || _typeof(entry) !== 'object') continue;
      var rec = entry;
      if (rec.type !== 'link') continue;
      if (!Array.isArray(rec.value)) continue;
      var _iterator6 = _createForOfIteratorHelper(rec.value),
        _step6;
      try {
        for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
          var v = _step6.value;
          var n = Number(v);
          if (Number.isFinite(n) && n > 0) ids.push(Math.floor(n));
        }
      } catch (err) {
        _iterator6.e(err);
      } finally {
        _iterator6.f();
      }
    }
  } catch (err) {
    _iterator5.e(err);
  } finally {
    _iterator5.f();
  }
  return _toConsumableArray(new Set(ids));
}

/**
 * 返回列表中第一个带有效 duration.value（分钟）的商品时长。
 */
export function pickFirstDurationMinutesFromProducts(products) {
  var _iterator7 = _createForOfIteratorHelper(products),
    _step7;
  try {
    for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
      var _product$duration;
      var product = _step7.value;
      var value = product === null || product === void 0 || (_product$duration = product.duration) === null || _product$duration === void 0 ? void 0 : _product$duration.value;
      var n = Number(value);
      if (Number.isFinite(n) && n > 0) return Math.floor(n);
    }
  } catch (err) {
    _iterator7.e(err);
  } finally {
    _iterator7.f();
  }
  return undefined;
}

/** 是否存在 capacity.type === 'custom' 的商品 */
export function hasCustomCapacityProduct(products) {
  return products.some(function (p) {
    var _p$capacity;
    return (p === null || p === void 0 || (_p$capacity = p.capacity) === null || _p$capacity === void 0 ? void 0 : _p$capacity.type) === 'custom';
  });
}

/**
 * 根据预约规则商品的 resource.type 计算桌台是否已被"占满"。
 * - single：只要有 `lastOrderId` 即视为占用
 * - multiple：当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`（inclusive）内的 pax 之和 >= 总容量
 * - 其他（'capacity' / undefined）：返回 false，不施加限制
 */
export function computeResourceIsFull(params) {
  var resourceSelectType = params.resourceSelectType,
    lastOrderId = params.lastOrderId,
    capacityList = params.capacityList,
    capacity = params.capacity;
  if (resourceSelectType === 'single') return Boolean(lastOrderId);
  if (resourceSelectType !== 'multiple') return false;
  var totalCapacity = Number(capacity);
  if (!Number.isFinite(totalCapacity) || totalCapacity <= 0) return false;
  var now = dayjs();
  var occupied = 0;
  var _iterator8 = _createForOfIteratorHelper(capacityList || []),
    _step8;
  try {
    for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
      var slot = _step8.value;
      var start = dayjs(slot === null || slot === void 0 ? void 0 : slot.start_at);
      var end = dayjs(slot === null || slot === void 0 ? void 0 : slot.end_at);
      if (!start.isValid() || !end.isValid()) continue;
      if ((now.isAfter(start) || now.isSame(start)) && (now.isBefore(end) || now.isSame(end))) {
        var pax = Number(slot === null || slot === void 0 ? void 0 : slot.pax);
        if (Number.isFinite(pax) && pax > 0) occupied += pax;
      }
    }
  } catch (err) {
    _iterator8.e(err);
  } finally {
    _iterator8.f();
  }
  return occupied >= totalCapacity;
}

/**
 * 在商品列表中找到第一个 `capacity.type === 'custom'` 的商品，取其 `custom` 数组第一项的 min/max。
 * 仅返回有限数字字段；若均无法解析则返回 `undefined`。
 */
export function pickFirstCustomCapacityPaxBounds(products) {
  var _iterator9 = _createForOfIteratorHelper(products),
    _step9;
  try {
    for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
      var p = _step9.value;
      var cap = p === null || p === void 0 ? void 0 : p.capacity;
      if (!cap || cap.type !== 'custom') continue;
      if (!Array.isArray(cap.custom) || cap.custom.length === 0) continue;
      var row = cap.custom[0];
      if (!row || _typeof(row) !== 'object') continue;
      var raw = row;
      var out = {};
      if (raw.min !== null && raw.min !== undefined && raw.min !== '') {
        var min = Number(raw.min);
        if (Number.isFinite(min)) out.min = min;
      }
      if (raw.max !== null && raw.max !== undefined && raw.max !== '') {
        var max = Number(raw.max);
        if (Number.isFinite(max)) out.max = max;
      }
      if (out.min !== undefined || out.max !== undefined) return out;
    }
  } catch (err) {
    _iterator9.e(err);
  } finally {
    _iterator9.f();
  }
  return undefined;
}

/**
 * 第一个 `capacity.type === 'custom'` 的商品，取其 `custom[0].id`（提交 booking metadata.capacity 维度 id）。
 * 无匹配时返回 `undefined`，调用方应回退为 `0`。
 */
export function pickFirstCustomCapacityDimensionId(products) {
  var _iterator10 = _createForOfIteratorHelper(products),
    _step10;
  try {
    for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
      var p = _step10.value;
      var cap = p === null || p === void 0 ? void 0 : p.capacity;
      if (!cap || cap.type !== 'custom') continue;
      if (!Array.isArray(cap.custom) || cap.custom.length === 0) continue;
      var row = cap.custom[0];
      if (!row || _typeof(row) !== 'object') continue;
      var id = row.id;
      if (id === null || id === undefined || id === '') continue;
      if (typeof id === 'number' && Number.isFinite(id)) return id;
      if (typeof id === 'string') {
        var trimmed = id.trim();
        if (!trimmed) continue;
        return trimmed;
      }
    }
  } catch (err) {
    _iterator10.e(err);
  } finally {
    _iterator10.f();
  }
  return undefined;
}