function resolvePriceVariantId(row) {
  if (!row.variant) return null;
  return typeof row.variant === "string" ? row.variant : row.variant.id;
}
function resolvePriceOfferId(row) {
  if (!row.offer) return null;
  return typeof row.offer === "string" ? row.offer : row.offer.id;
}
function resolvePriceChannelId(row) {
  if (!row.offer) return row.channelId ?? null;
  if (typeof row.offer === "string") return row.channelId ?? null;
  return row.channelId ?? row.offer.channelId ?? null;
}
function resolvePriceKindCode(row) {
  if (row.priceKind) {
    if (typeof row.priceKind === "string") return row.priceKind;
    return row.priceKind.code ?? row.kind ?? "";
  }
  return row.kind ?? "";
}
function matchesContext(row, ctx) {
  const { quantity, date } = ctx;
  if (row.minQuantity && quantity < row.minQuantity) return false;
  if (row.maxQuantity && quantity > row.maxQuantity) return false;
  if (row.startsAt && date < row.startsAt) return false;
  if (row.endsAt && date > row.endsAt) return false;
  if (row.channelId || row.offer && resolvePriceChannelId(row)) {
    const channel = resolvePriceChannelId(row);
    if (channel && ctx.channelId && channel !== ctx.channelId) return false;
    if (channel && !ctx.channelId) return false;
  }
  if (row.userId && ctx.userId !== row.userId) return false;
  if (row.userGroupId && ctx.userGroupId !== row.userGroupId) return false;
  if (row.customerId && ctx.customerId !== row.customerId) return false;
  if (row.customerGroupId && ctx.customerGroupId !== row.customerGroupId) return false;
  if (ctx.offerId && resolvePriceOfferId(row) && resolvePriceOfferId(row) !== ctx.offerId) return false;
  return true;
}
function scorePrice(row) {
  const resolvedKind = resolvePriceKindCode(row);
  let score = 0;
  if (resolvedKind === "custom") score += 5;
  else if (resolvedKind === "tier") score += 3;
  else if (resolvedKind === "promotion" || row.priceKind?.isPromotion) score += 4;
  else score += 2;
  if (row.variant) score += 8;
  if (row.offer) score += 6;
  if (row.channelId) score += 5;
  if (row.userId) score += 5;
  if (row.userGroupId) score += 4;
  if (row.customerId) score += 4;
  if (row.customerGroupId) score += 3;
  if (row.minQuantity && row.minQuantity > 1) score += 1;
  return score;
}
function selectBestPrice(rows, ctx) {
  const candidates = rows.filter((row) => matchesContext(row, ctx));
  if (!candidates.length) return null;
  candidates.sort((a, b) => {
    const scoreDiff = scorePrice(b) - scorePrice(a);
    if (scoreDiff !== 0) return scoreDiff;
    const startA = a.startsAt ? a.startsAt.getTime() : 0;
    const startB = b.startsAt ? b.startsAt.getTime() : 0;
    if (startA !== startB) return startB - startA;
    if (resolvePriceKindCode(a) === resolvePriceKindCode(b)) {
      return (b.minQuantity ?? 1) - (a.minQuantity ?? 1);
    }
    return (a.minQuantity ?? 1) - (b.minQuantity ?? 1);
  });
  return candidates[0];
}
const pricingResolvers = [];
function sortResolvers() {
  pricingResolvers.sort((a, b) => b.priority - a.priority);
}
function registerCatalogPricingResolver(resolver, options) {
  pricingResolvers.push({ resolver, priority: options?.priority ?? 0 });
  sortResolvers();
}
function resetCatalogPricingResolvers() {
  pricingResolvers.splice(0, pricingResolvers.length);
}
async function resolveCatalogPrice(rows, ctx, options) {
  let workingRows = rows;
  let workingContext = ctx;
  const eventBus = options?.eventBus ?? null;
  let resolved;
  if (eventBus) {
    await eventBus.emitEvent("catalog.pricing.resolve.before", {
      rows: workingRows,
      context: workingContext,
      setRows(next) {
        if (Array.isArray(next)) workingRows = next;
      },
      setContext(next) {
        if (next) workingContext = next;
      },
      setResult(next) {
        resolved = next;
      }
    });
    if (resolved !== void 0) return resolved;
  }
  for (const { resolver } of pricingResolvers) {
    const result = await resolver(workingRows, workingContext);
    if (result !== void 0) {
      resolved = result ?? null;
      break;
    }
  }
  if (resolved === void 0) {
    resolved = selectBestPrice(workingRows, workingContext);
  }
  if (eventBus) {
    await eventBus.emitEvent("catalog.pricing.resolve.after", {
      rows: workingRows,
      context: workingContext,
      result: resolved ?? null,
      setResult(next) {
        resolved = next;
      }
    });
  }
  return resolved ?? null;
}
async function resolveCatalogPriceBatch(entries, options) {
  return Promise.all(
    entries.map(({ rows, context }) => resolveCatalogPrice(rows, context, options))
  );
}
export {
  registerCatalogPricingResolver,
  resetCatalogPricingResolvers,
  resolveCatalogPrice,
  resolveCatalogPriceBatch,
  resolvePriceChannelId,
  resolvePriceKindCode,
  resolvePriceOfferId,
  resolvePriceVariantId,
  selectBestPrice
};
//# sourceMappingURL=pricing.js.map
