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/solution/ShopDiscount/utils.ts
var utils_exports = {};
__export(utils_exports, {
  calculateOrderLevelDiscountAllocation: () => calculateOrderLevelDiscountAllocation,
  filterDiscountListByBookingTime: () => filterDiscountListByBookingTime,
  getDateIsInSchedule: () => getDateIsInSchedule,
  getDiscountAmount: () => getDiscountAmount,
  getDiscountListAmount: () => getDiscountListAmount,
  getDiscountListAmountTotal: () => getDiscountListAmountTotal,
  isAllNormalProduct: () => isAllNormalProduct,
  isNormalProductByDurationSchedule: () => isNormalProductByDurationSchedule,
  isOrderLevelFixedAmountDiscount: () => isOrderLevelFixedAmountDiscount,
  uniqueById: () => uniqueById
});
module.exports = __toCommonJS(utils_exports);
var import_decimal = __toESM(require("decimal.js"));
var import_dayjs = __toESM(require("dayjs"));
var uniqueById = (arr, key = "id") => {
  const seen = /* @__PURE__ */ new Set();
  return arr.filter((item) => !seen.has(item[key]) && seen.add(item[key]));
};
var isNormalProductByDurationSchedule = (item) => {
  var _a, _b;
  return !(item == null ? void 0 : item.duration) && !((_a = item == null ? void 0 : item.schedules) == null ? void 0 : _a.length) && !((_b = item == null ? void 0 : item["schedule.ids"]) == null ? void 0 : _b.length);
};
var isAllNormalProduct = (items) => {
  return items.every((item) => isNormalProductByDurationSchedule(item));
};
var getDiscountAmount = (discount, total, price) => {
  var _a;
  if (discount.tag === "good_pass") {
    return new import_decimal.default(price).minus(new import_decimal.default(price || 0)).toNumber();
  }
  const isFixedAmount = ((_a = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a.discount_card_type) === "fixed_amount";
  if (isFixedAmount) {
    return Math.max(new import_decimal.default(price).minus(new import_decimal.default((discount.amount ?? discount.par_value) || 0)).toNumber(), 0);
  }
  return new import_decimal.default(100).minus(discount.par_value || 0).div(100).mul(new import_decimal.default(price)).toNumber();
};
var getDiscountListAmountTotal = (discount) => {
  return discount.reduce((acc, cur) => {
    return new import_decimal.default(acc).plus(new import_decimal.default(cur.num || 1).mul(new import_decimal.default(cur.amount || 0))).toNumber();
  }, new import_decimal.default(0));
};
var getDiscountListAmount = (discount) => {
  return discount.reduce((acc, cur) => {
    return new import_decimal.default(acc).plus(new import_decimal.default(cur.amount || 0)).toNumber();
  }, new import_decimal.default(0));
};
var getDateIsInSchedule = (dateTime, scheduleList) => {
  if (!dateTime || !scheduleList || scheduleList.length === 0) {
    return false;
  }
  const targetDate = (0, import_dayjs.default)(dateTime);
  if (!targetDate.isValid()) {
    return false;
  }
  for (const schedule of scheduleList) {
    if (isTimeInScheduleItem(dateTime, schedule)) {
      return true;
    }
  }
  return false;
};
var isTimeInScheduleItem = (dateTime, schedule) => {
  const targetDate = (0, import_dayjs.default)(dateTime);
  const targetDateString = dateTime.split(" ")[0];
  const targetTimeString = dateTime.split(" ")[1] || "00:00:00";
  switch (schedule.type) {
    case "standard":
      return isInStandardSchedule(targetDate, targetDateString, targetTimeString, schedule);
    case "time-slots":
      return isInTimeSlotsSchedule(targetDate, targetDateString, targetTimeString, schedule);
    case "designation":
      return isInDesignationSchedule(targetDate, targetDateString, targetTimeString, schedule);
    default:
      return false;
  }
};
var isInStandardSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
  if (!schedule.start_time || !schedule.end_time) {
    return false;
  }
  const startDate = (0, import_dayjs.default)(schedule.start_time);
  const endDate = (0, import_dayjs.default)(schedule.end_time);
  const isInBasicRange = targetDate.isSameOrAfter(startDate) && targetDate.isSameOrBefore(endDate);
  if (schedule.repeat_type === "none") {
    return isInBasicRange;
  }
  return isInRepeatingSchedule(targetDate, targetDateString, targetTimeString, schedule, startDate, endDate);
};
var isInTimeSlotsSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
  if (!schedule.start_time) {
    return false;
  }
  if (schedule.repeat_type === "none") {
    const scheduleDate = schedule.start_time.split(" ")[0];
    if (targetDateString !== scheduleDate) {
      return false;
    }
    return checkTimeSlotsForDate(targetDate, targetDateString, schedule.time_slot);
  }
  return isInTimeSlotsRepeatingSchedule(targetDate, targetDateString, targetTimeString, schedule);
};
var isInDesignationSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
  if (!schedule.designation) {
    return false;
  }
  for (const designation of schedule.designation) {
    const startDateTime = `${designation.start_date} ${designation.start_time}:00`;
    const endDateTime = `${designation.end_date} ${designation.end_time}:00`;
    const startDate = (0, import_dayjs.default)(startDateTime);
    const endDate = (0, import_dayjs.default)(endDateTime);
    if (targetDate.isSameOrAfter(startDate) && targetDate.isSameOrBefore(endDate)) {
      return true;
    }
  }
  return false;
};
var isInRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule, startDate, endDate) => {
  if (!schedule.repeat_rule) {
    return false;
  }
  const { repeat_rule, repeat_type } = schedule;
  const targetDateOnly = (0, import_dayjs.default)(targetDateString);
  if (repeat_rule.included_date && repeat_rule.included_date.length > 0) {
    for (const includedDate of repeat_rule.included_date) {
      const includeStartDate = (0, import_dayjs.default)(includedDate.start);
      const includeEndDate = (0, import_dayjs.default)(includedDate.end);
      if (targetDateOnly.isSameOrAfter(includeStartDate, "day") && targetDateOnly.isSameOrBefore(includeEndDate, "day")) {
        return true;
      }
    }
  }
  for (const excludedDate of repeat_rule.excluded_date) {
    const excludeStartDate = (0, import_dayjs.default)(excludedDate.start);
    const excludeEndDate = (0, import_dayjs.default)(excludedDate.end);
    if (targetDateOnly.isSameOrAfter(excludeStartDate, "day") && targetDateOnly.isSameOrBefore(excludeEndDate, "day")) {
      return false;
    }
  }
  if (repeat_rule.end.type === "date" && repeat_rule.end.end_date) {
    const ruleEndDate = (0, import_dayjs.default)(repeat_rule.end.end_date);
    if (targetDate.isAfter(ruleEndDate)) {
      return false;
    }
  }
  switch (repeat_type) {
    case "daily":
      return isInDailyRepeat(targetDate, startDate, endDate, repeat_rule);
    case "weekly":
      return isInWeeklyRepeat(targetDate, startDate, endDate, repeat_rule);
    default:
      return false;
  }
};
var isInDailyRepeat = (targetDate, startDate, endDate, repeatRule) => {
  const daysDiff = targetDate.diff(startDate, "day");
  if (daysDiff < 0) {
    return false;
  }
  if (daysDiff % repeatRule.frequency !== 0) {
    return false;
  }
  const targetTimeOfDay = targetDate.hour() * 3600 + targetDate.minute() * 60 + targetDate.second();
  const startTimeOfDay = startDate.hour() * 3600 + startDate.minute() * 60 + startDate.second();
  const endTimeOfDay = endDate.hour() * 3600 + endDate.minute() * 60 + endDate.second();
  return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay <= endTimeOfDay;
};
var isInWeeklyRepeat = (targetDate, startDate, endDate, repeatRule) => {
  const targetDayOfWeek = targetDate.day();
  if (!repeatRule.frequency_date.includes(targetDayOfWeek)) {
    return false;
  }
  const weeksDiff = targetDate.diff(startDate, "week");
  if (weeksDiff < 0) {
    return false;
  }
  if (weeksDiff % repeatRule.frequency !== 0) {
    return false;
  }
  const targetTimeOfDay = targetDate.hour() * 3600 + targetDate.minute() * 60 + targetDate.second();
  const startTimeOfDay = startDate.hour() * 3600 + startDate.minute() * 60 + startDate.second();
  const endTimeOfDay = endDate.hour() * 3600 + endDate.minute() * 60 + endDate.second();
  return targetTimeOfDay >= startTimeOfDay && targetTimeOfDay <= endTimeOfDay;
};
var isInTimeSlotsRepeatingSchedule = (targetDate, targetDateString, targetTimeString, schedule) => {
  if (!schedule.repeat_rule || !schedule.start_time) {
    return false;
  }
  const { repeat_rule, repeat_type } = schedule;
  const startDate = (0, import_dayjs.default)(schedule.start_time);
  const targetDateOnly = (0, import_dayjs.default)(targetDateString);
  if (repeat_rule.included_date && repeat_rule.included_date.length > 0) {
    for (const includedDate of repeat_rule.included_date) {
      const includeStartDate = (0, import_dayjs.default)(includedDate.start);
      const includeEndDate = (0, import_dayjs.default)(includedDate.end);
      if (targetDateOnly.isSameOrAfter(includeStartDate, "day") && targetDateOnly.isSameOrBefore(includeEndDate, "day")) {
        return checkTimeSlotsForDate(targetDate, targetDateString, schedule.time_slot);
      }
    }
  }
  for (const excludedDate of repeat_rule.excluded_date) {
    const excludeStartDate = (0, import_dayjs.default)(excludedDate.start);
    const excludeEndDate = (0, import_dayjs.default)(excludedDate.end);
    if (targetDateOnly.isSameOrAfter(excludeStartDate, "day") && targetDateOnly.isSameOrBefore(excludeEndDate, "day")) {
      return false;
    }
  }
  if (repeat_rule.end.type === "date" && repeat_rule.end.end_date) {
    const ruleEndDate = (0, import_dayjs.default)(repeat_rule.end.end_date);
    if (targetDateOnly.isAfter(ruleEndDate, "day")) {
      return false;
    }
  }
  let isDateValid = false;
  switch (repeat_type) {
    case "daily":
      isDateValid = isInDailyRepeatForDate(targetDateOnly, startDate, repeat_rule);
      break;
    case "weekly":
      isDateValid = isInWeeklyRepeatForDate(targetDateOnly, startDate, repeat_rule);
      break;
    default:
      return false;
  }
  if (isDateValid) {
    return checkTimeSlotsForDate(targetDate, targetDateString, schedule.time_slot);
  }
  return false;
};
var checkTimeSlotsForDate = (targetDate, targetDateString, timeSlots) => {
  for (const timeSlot of timeSlots) {
    const slotStart = `${targetDateString} ${timeSlot.start_time}:00`;
    const slotEnd = `${targetDateString} ${timeSlot.end_time}:00`;
    const slotStartDate = (0, import_dayjs.default)(slotStart);
    const slotEndDate = (0, import_dayjs.default)(slotEnd);
    if (targetDate.isSameOrAfter(slotStartDate) && targetDate.isSameOrBefore(slotEndDate)) {
      return true;
    }
  }
  return false;
};
var isInDailyRepeatForDate = (targetDate, startDate, repeatRule) => {
  const daysDiff = targetDate.diff(startDate, "day");
  if (daysDiff < 0) {
    return false;
  }
  return daysDiff % repeatRule.frequency === 0;
};
var isInWeeklyRepeatForDate = (targetDate, startDate, repeatRule) => {
  const targetDayOfWeek = targetDate.day();
  if (!repeatRule.frequency_date.includes(targetDayOfWeek)) {
    return false;
  }
  const weeksDiff = targetDate.diff(startDate, "week");
  if (weeksDiff < 0) {
    return false;
  }
  return weeksDiff % repeatRule.frequency === 0;
};
var filterDiscountListByBookingTime = (discountList, bookingTime) => {
  if (!bookingTime) {
    return discountList;
  }
  return discountList.filter((discount) => {
    var _a, _b;
    if (((_a = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a.validity_type) === "custom_schedule_validity") {
      return getDateIsInSchedule(bookingTime, ((_b = discount.custom_schedule_snapshot) == null ? void 0 : _b.data) || []);
    }
    try {
      const isHasStart = !!discount.start_date && !!discount.start_time;
      const startDate = (0, import_dayjs.default)(`${discount.start_date} ${discount.start_time}`);
      const bookingTimeDayjs = (0, import_dayjs.default)(bookingTime);
      const isAfterStart = isHasStart ? bookingTimeDayjs.isSameOrAfter(startDate) : true;
      const isBeforeExpire = discount.expire_time ? bookingTimeDayjs.isSameOrBefore((0, import_dayjs.default)(discount.expire_time)) : true;
      return isAfterStart && isBeforeExpire;
    } catch (error) {
      return true;
    }
  });
};
var isOrderLevelFixedAmountDiscount = (discount) => {
  var _a, _b;
  return discount.tag === "product_discount_card" && ((_a = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a.discount_card_type) === "fixed_amount" && ((_b = discount == null ? void 0 : discount.metadata) == null ? void 0 : _b.discount_calculation_mode) === "order_level";
};
var calculateOrderLevelDiscountAllocation = (discount, applicableProducts) => {
  const result = /* @__PURE__ */ new Map();
  if (applicableProducts.length === 0) {
    return result;
  }
  const totalAmount = applicableProducts.reduce((acc, product) => {
    return new import_decimal.default(acc).plus(new import_decimal.default(product.amount).mul(product.quantity)).toNumber();
  }, 0);
  if (totalAmount <= 0) {
    return result;
  }
  const fixedAmount = new import_decimal.default(discount.par_value || 0).toNumber();
  const actualDiscountTotal = Math.min(fixedAmount, totalAmount);
  let allocatedTotal = new import_decimal.default(0);
  applicableProducts.forEach((product) => {
    const rawDiscountPerItem = new import_decimal.default(product.amount).div(totalAmount).mul(actualDiscountTotal);
    const discountAmountPerItem = rawDiscountPerItem.toDecimalPlaces(2, import_decimal.default.ROUND_DOWN).toNumber();
    result.set(product.productId, {
      discountAmount: discountAmountPerItem,
      // 单价折扣金额
      difference: 0
      // 默认差值为0
    });
    allocatedTotal = allocatedTotal.plus(
      new import_decimal.default(discountAmountPerItem).mul(product.quantity)
    );
  });
  const totalDifference = new import_decimal.default(actualDiscountTotal).minus(allocatedTotal).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber();
  if (totalDifference > 0) {
    const isSingleQuantity = (product) => {
      if (product.parentQuantity !== void 0) {
        return product.quantity === 1 && product.parentQuantity === 1;
      }
      return product.quantity === 1;
    };
    const singleQuantityProducts = applicableProducts.filter(isSingleQuantity);
    if (singleQuantityProducts.length > 0) {
      const productsWithEnoughSpace = singleQuantityProducts.filter((product) => {
        const allocation = result.get(product.productId);
        if (!allocation)
          return false;
        const remainingSpace = new import_decimal.default(product.amount).minus(allocation.discountAmount).toNumber();
        return remainingSpace >= totalDifference;
      });
      if (productsWithEnoughSpace.length > 0) {
        productsWithEnoughSpace.sort((a, b) => b.amount - a.amount);
        const targetProduct = productsWithEnoughSpace[0];
        const targetAllocation = result.get(targetProduct.productId);
        if (targetAllocation) {
          result.set(targetProduct.productId, {
            discountAmount: new import_decimal.default(targetAllocation.discountAmount).plus(totalDifference).toNumber(),
            difference: 0
            // 不需要存储差值
          });
        }
      } else {
        singleQuantityProducts.sort((a, b) => b.amount - a.amount);
        const targetProduct = singleQuantityProducts[0];
        const targetAllocation = result.get(targetProduct.productId);
        if (targetAllocation) {
          result.set(targetProduct.productId, {
            ...targetAllocation,
            difference: totalDifference
          });
        }
      }
    } else {
      const lastProduct = applicableProducts[applicableProducts.length - 1];
      const lastProductAllocation = result.get(lastProduct.productId);
      if (lastProductAllocation) {
        result.set(lastProduct.productId, {
          ...lastProductAllocation,
          difference: totalDifference
        });
      }
    }
  }
  return result;
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  calculateOrderLevelDiscountAllocation,
  filterDiscountListByBookingTime,
  getDateIsInSchedule,
  getDiscountAmount,
  getDiscountListAmount,
  getDiscountListAmountTotal,
  isAllNormalProduct,
  isNormalProductByDurationSchedule,
  isOrderLevelFixedAmountDiscount,
  uniqueById
});
