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 _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 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 _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 _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
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; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
import dayjs from 'dayjs';
import Decimal from 'decimal.js';
export function isBusinessHoursCrossDay(config) {
  var _config$businessStart = config.businessStartTime.split(':').map(Number),
    _config$businessStart2 = _slicedToArray(_config$businessStart, 2),
    startH = _config$businessStart2[0],
    startM = _config$businessStart2[1];
  var _config$businessEndTi = config.businessEndTime.split(':').map(Number),
    _config$businessEndTi2 = _slicedToArray(_config$businessEndTi, 2),
    endH = _config$businessEndTi2[0],
    endM = _config$businessEndTi2[1];
  return endH < startH || endH === startH && endM <= startM;
}
export function generateTimeLabels(config) {
  var slotDurationMinutes = config.slotDurationMinutes,
    businessStartTime = config.businessStartTime,
    businessEndTime = config.businessEndTime;
  var labels = [];
  var baseDate = '2000-01-01';
  var cursor = dayjs("".concat(baseDate, " ").concat(businessStartTime));
  var crossDay = isBusinessHoursCrossDay(config);
  var endBase = crossDay ? '2000-01-02' : baseDate;
  var end = dayjs("".concat(endBase, " ").concat(businessEndTime));
  while (cursor.isBefore(end)) {
    labels.push(cursor.format('HH:mm'));
    cursor = cursor.add(slotDurationMinutes, 'minute');
  }
  return labels;
}
export function isSlotOccupied(slotStart, slotEnd, occupiedTimes) {
  var _iterator = _createForOfIteratorHelper(occupiedTimes),
    _step;
  try {
    for (_iterator.s(); !(_step = _iterator.n()).done;) {
      var occupied = _step.value;
      var occStart = dayjs(occupied.start_at);
      var occEnd = dayjs(occupied.end_at);
      if (slotStart.isBefore(occEnd) && slotEnd.isAfter(occStart)) {
        return true;
      }
    }
  } catch (err) {
    _iterator.e(err);
  } finally {
    _iterator.f();
  }
  return false;
}
function isSlotWithinResourceTimes(slotStart, slotEnd, resourceTimes) {
  var _iterator2 = _createForOfIteratorHelper(resourceTimes),
    _step2;
  try {
    for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
      var t = _step2.value;
      var tStart = dayjs(t.start_at);
      var tEnd = dayjs(t.end_at);
      if (slotStart.isBefore(tEnd) && slotEnd.isAfter(tStart)) return true;
    }
  } catch (err) {
    _iterator2.e(err);
  } finally {
    _iterator2.f();
  }
  return false;
}
function getResourceTimesForDate(resource, date, config) {
  var crossDay = isBusinessHoursCrossDay(config);
  var dayStart = dayjs("".concat(date, " ").concat(config.businessStartTime));
  var dayEnd = crossDay ? dayjs("".concat(date, " ").concat(config.businessEndTime)).add(1, 'day') : dayjs("".concat(date, " ").concat(config.businessEndTime));
  return resource.times.filter(function (t) {
    var tStart = dayjs(t.start_at);
    var tEnd = dayjs(t.end_at);
    return tStart.isBefore(dayEnd) && tEnd.isAfter(dayStart);
  });
}
export function collectEventsForDate(resource, date, config) {
  var timesForDate = getResourceTimesForDate(resource, date, config);
  var events = [];
  var _iterator3 = _createForOfIteratorHelper(timesForDate),
    _step3;
  try {
    for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
      var t = _step3.value;
      if (Array.isArray(t.event_list)) {
        var _iterator4 = _createForOfIteratorHelper(t.event_list),
          _step4;
        try {
          for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
            var _evt$pax;
            var evt = _step4.value;
            events.push({
              start_at: evt.start_at,
              end_at: evt.end_at,
              pax: (_evt$pax = evt.pax) !== null && _evt$pax !== void 0 ? _evt$pax : 1
            });
          }
        } catch (err) {
          _iterator4.e(err);
        } finally {
          _iterator4.f();
        }
      }
    }
  } catch (err) {
    _iterator3.e(err);
  } finally {
    _iterator3.f();
  }
  return events;
}
export function computeSlotStatus(params) {
  var slotStart = params.slotStart,
    slotEnd = params.slotEnd,
    events = params.events,
    resourceType = params.resourceType,
    capacity = params.capacity;
  var overlapping = events.filter(function (evt) {
    var evtStart = dayjs(evt.start_at);
    var evtEnd = dayjs(evt.end_at);
    return slotStart.isBefore(evtEnd) && slotEnd.isAfter(evtStart);
  });
  if (resourceType === 'single') {
    if (overlapping.length > 0) return {
      status: 'occupied',
      remainingCapacity: 0
    };
    return {
      status: 'available',
      remainingCapacity: 1
    };
  }
  var usedCapacity = overlapping.reduce(function (sum, evt) {
    return sum + evt.pax;
  }, 0);
  var remaining = Math.max(0, capacity - usedCapacity);
  if (remaining <= 0) return {
    status: 'occupied',
    remainingCapacity: 0
  };
  if (remaining < capacity) return {
    status: 'partially_occupied',
    remainingCapacity: remaining
  };
  return {
    status: 'available',
    remainingCapacity: remaining
  };
}

/**
 * 合并多个子商品的同一个时段为一个"外层 slot"。
 * - status 取优先级最高的（available > partially_occupied > occupied > unavailable / past）
 * - price 取非空子 slot 中最小的那个
 * - 其它字段使用第一个参考子 slot（外层 slot 不带 productId）
 */
function mergeSubSlots(subSlots) {
  var priority = {
    available: 5,
    partially_occupied: 4,
    occupied: 3,
    unavailable: 2,
    past: 1
  };
  var best = subSlots[0];
  var _iterator5 = _createForOfIteratorHelper(subSlots),
    _step5;
  try {
    for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
      var _priority$slot$status, _priority$best$status;
      var slot = _step5.value;
      if (((_priority$slot$status = priority[slot.status]) !== null && _priority$slot$status !== void 0 ? _priority$slot$status : 0) > ((_priority$best$status = priority[best.status]) !== null && _priority$best$status !== void 0 ? _priority$best$status : 0)) best = slot;
    }
  } catch (err) {
    _iterator5.e(err);
  } finally {
    _iterator5.f();
  }
  var minPrice = null;
  var _iterator6 = _createForOfIteratorHelper(subSlots),
    _step6;
  try {
    for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
      var _slot = _step6.value;
      if (_slot.price == null) continue;
      var decimal = new Decimal(_slot.price || '0');
      if (!minPrice || decimal.lt(minPrice)) minPrice = decimal;
    }
  } catch (err) {
    _iterator6.e(err);
  } finally {
    _iterator6.f();
  }
  return {
    startTime: best.startTime,
    endTime: best.endTime,
    status: best.status,
    price: minPrice ? minPrice.toFixed(2) : null,
    resourceId: best.resourceId,
    resourceFormId: best.resourceFormId,
    capacity: best.capacity,
    remainingCapacity: best.remainingCapacity
  };
}
function buildProductSlots(params) {
  var date = params.date,
    config = params.config,
    resource = params.resource,
    mapping = params.mapping,
    timeLabels = params.timeLabels,
    timesForDate = params.timesForDate,
    events = params.events,
    resCapacity = params.resCapacity,
    now = params.now,
    crossDay = params.crossDay,
    quotationPriceMap = params.quotationPriceMap,
    childRawResources = params.childRawResources,
    childTimesCache = params.childTimesCache,
    childEventsCache = params.childEventsCache,
    config_businessStartHour = params.config_businessStartHour;
  var slots = [];
  var _iterator7 = _createForOfIteratorHelper(timeLabels),
    _step7;
  try {
    for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
      var _quotationPriceMap$ge;
      var label = _step7.value;
      var _label$split$map = label.split(':').map(Number),
        _label$split$map2 = _slicedToArray(_label$split$map, 1),
        h = _label$split$map2[0];
      var isNextDay = crossDay && h < config_businessStartHour;
      var slotDate = isNextDay ? dayjs(date).add(1, 'day').format('YYYY-MM-DD') : date;
      var slotStart = dayjs("".concat(slotDate, " ").concat(label));
      var slotEnd = slotStart.add(config.slotDurationMinutes, 'minute');
      var status = void 0;
      var remainingCapacity = null;
      if (slotStart.isBefore(now)) {
        status = 'past';
      } else if (!isSlotWithinResourceTimes(slotStart, slotEnd, timesForDate)) {
        status = 'unavailable';
      } else {
        var result = computeSlotStatus({
          slotStart: slotStart,
          slotEnd: slotEnd,
          events: events,
          resourceType: mapping.resourceType,
          capacity: resCapacity
        });
        status = result.status;
        remainingCapacity = result.remainingCapacity;
        if (status !== 'occupied' && childRawResources && childRawResources.length) {
          for (var i = 0; i < childRawResources.length; i++) {
            var _childTimesCache$i, _childEventsCache$i, _child$capacity;
            var child = childRawResources[i];
            var childTimes = (_childTimesCache$i = childTimesCache === null || childTimesCache === void 0 ? void 0 : childTimesCache[i]) !== null && _childTimesCache$i !== void 0 ? _childTimesCache$i : getResourceTimesForDate(child, date, config);
            var childEvents = (_childEventsCache$i = childEventsCache === null || childEventsCache === void 0 ? void 0 : childEventsCache[i]) !== null && _childEventsCache$i !== void 0 ? _childEventsCache$i : collectEventsForDate(child, date, config);
            if (!isSlotWithinResourceTimes(slotStart, slotEnd, childTimes)) {
              status = 'unavailable';
              remainingCapacity = null;
              break;
            }
            var childType = child.type || 'single';
            var childResult = computeSlotStatus({
              slotStart: slotStart,
              slotEnd: slotEnd,
              events: childEvents,
              resourceType: childType,
              capacity: (_child$capacity = child.capacity) !== null && _child$capacity !== void 0 ? _child$capacity : 1
            });
            if (childResult.status === 'occupied') {
              status = 'occupied';
              remainingCapacity = 0;
              break;
            }
            if (childResult.status === 'partially_occupied' && status === 'available') {
              var _remainingCapacity;
              status = 'partially_occupied';
              remainingCapacity = Math.min((_remainingCapacity = remainingCapacity) !== null && _remainingCapacity !== void 0 ? _remainingCapacity : childResult.remainingCapacity, childResult.remainingCapacity);
            }
          }
        }
      }
      var isBookable = status === 'available' || status === 'partially_occupied';
      var slotStartStr = slotStart.format('YYYY-MM-DD HH:mm');
      slots.push({
        startTime: slotStartStr,
        endTime: slotEnd.format('YYYY-MM-DD HH:mm'),
        status: status,
        price: isBookable ? (_quotationPriceMap$ge = quotationPriceMap === null || quotationPriceMap === void 0 ? void 0 : quotationPriceMap.get("".concat(mapping.productId, ":").concat(slotStartStr))) !== null && _quotationPriceMap$ge !== void 0 ? _quotationPriceMap$ge : mapping.price : null,
        resourceId: resource.resourceId,
        resourceFormId: resource.formId,
        capacity: status === 'past' || status === 'unavailable' ? null : resCapacity,
        remainingCapacity: remainingCapacity,
        productId: mapping.productId
      });
    }
  } catch (err) {
    _iterator7.e(err);
  } finally {
    _iterator7.f();
  }
  return slots;
}
export function buildTimeSlotGrid(params) {
  var date = params.date,
    config = params.config,
    rawResources = params.rawResources,
    resourceProductMap = params.resourceProductMap,
    quotationPriceMap = params.quotationPriceMap;
  var timeLabels = generateTimeLabels(config);
  var now = dayjs();
  var crossDay = isBusinessHoursCrossDay(config);
  var config_businessStartHour = Number(config.businessStartTime.split(':')[0]);
  var rawResourceById = new Map();
  var _iterator8 = _createForOfIteratorHelper(rawResources),
    _step8;
  try {
    for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
      var item = _step8.value;
      rawResourceById.set(item.resourceId, item);
    }
  } catch (err) {
    _iterator8.e(err);
  } finally {
    _iterator8.f();
  }
  var resources = [];
  var _iterator9 = _createForOfIteratorHelper(rawResources),
    _step9;
  try {
    var _loop = function _loop() {
      var _resource$capacity;
      var resource = _step9.value;
      var mappings = resourceProductMap.get(resource.resourceId);
      if (!mappings || !mappings.length) return 1; // continue
      var timesForDate = getResourceTimesForDate(resource, date, config);
      var events = collectEventsForDate(resource, date, config);
      var resCapacity = (_resource$capacity = resource.capacity) !== null && _resource$capacity !== void 0 ? _resource$capacity : 1;
      var combined = resource.combined_resource;
      var isCombined = !!(combined && combined.status === 1 && Array.isArray(combined.resource_ids) && combined.resource_ids.length);
      var childRawResources = isCombined ? combined.resource_ids.map(function (id) {
        return rawResourceById.get(id);
      }).filter(function (r) {
        return !!r;
      }) : undefined;
      var childTimesCache = childRawResources === null || childRawResources === void 0 ? void 0 : childRawResources.map(function (child) {
        return getResourceTimesForDate(child, date, config);
      });
      var childEventsCache = childRawResources === null || childRawResources === void 0 ? void 0 : childRawResources.map(function (child) {
        return collectEventsForDate(child, date, config);
      });
      var subRows = mappings.map(function (mapping) {
        var productSlots = buildProductSlots({
          date: date,
          config: config,
          resource: resource,
          mapping: mapping,
          timeLabels: timeLabels,
          timesForDate: timesForDate,
          events: events,
          resCapacity: resCapacity,
          now: now,
          crossDay: crossDay,
          quotationPriceMap: quotationPriceMap,
          childRawResources: childRawResources,
          childTimesCache: childTimesCache,
          childEventsCache: childEventsCache,
          config_businessStartHour: config_businessStartHour
        });
        return {
          productId: mapping.productId,
          productTitle: mapping.productTitle,
          price: mapping.price,
          slots: productSlots
        };
      });
      var hasMultipleProducts = subRows.length > 1;
      var primary = mappings[0];
      var outerSlots;
      if (hasMultipleProducts) {
        outerSlots = timeLabels.map(function (_label, slotIndex) {
          var group = subRows.map(function (row) {
            return row.slots[slotIndex];
          });
          return mergeSubSlots(group);
        });
      } else {
        outerSlots = subRows[0].slots.map(function (slot) {
          return _objectSpread(_objectSpread({}, slot), {}, {
            productId: undefined
          });
        });
      }
      var row = {
        resourceId: resource.resourceId,
        resourceFormId: resource.formId,
        resourceName: resource.main_field || primary.resourceName,
        productId: primary.productId,
        productTitle: primary.productTitle,
        slots: outerSlots
      };
      if (hasMultipleProducts) {
        row.products = subRows;
        row.hasMultipleProducts = true;
      }
      if (isCombined && combined) {
        row.combinedResource = {
          resourceIds: _toConsumableArray(combined.resource_ids)
        };
      }
      resources.push(row);
    };
    for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
      if (_loop()) continue;
    }

    // 按 productId 分组排序，确保同一商品的场地连续排列
  } catch (err) {
    _iterator9.e(err);
  } finally {
    _iterator9.f();
  }
  var productOrder = new Map();
  for (var _i = 0, _resources = resources; _i < _resources.length; _i++) {
    var row = _resources[_i];
    if (!productOrder.has(row.productId)) productOrder.set(row.productId, productOrder.size);
  }
  resources.sort(function (a, b) {
    var _productOrder$get, _productOrder$get2;
    return ((_productOrder$get = productOrder.get(a.productId)) !== null && _productOrder$get !== void 0 ? _productOrder$get : 0) - ((_productOrder$get2 = productOrder.get(b.productId)) !== null && _productOrder$get2 !== void 0 ? _productOrder$get2 : 0);
  });
  return {
    date: date,
    timeLabels: timeLabels,
    resources: resources
  };
}