import { AdEngine } from './AdEngine';
export class AdSupplier {
  static #instance;
  constructor() {}
  static get instance() {
    if (!AdSupplier.#instance) {
      AdSupplier.#instance = new AdSupplier();
    }
    return AdSupplier.#instance;
  }
  recommendedAds({
    ads,
    count,
    communityId
  }) {
    // calculate impression age
    const impressionAges = this.calculateImpressionAges(ads);

    // calculate score for all ads
    const scores = new Map();
    ads.forEach(ad => {
      var _ad$target;
      const relevancy = (((_ad$target = ad.target) === null || _ad$target === void 0 ? void 0 : _ad$target.communityIds) || []).includes(communityId || '') ? 1 : 0;
      const impressionAge = impressionAges.get(ad.adId);
      if (impressionAge == null) return;
      const score = relevancy + Math.pow(Math.E, 2 * impressionAge);
      scores.set(ad.adId, score);
    });
    return this.selectAdsByWeightedRandomChoice({
      ads,
      scores,
      count
    });
  }
  calculateImpressionAges(ads) {
    var _recencySortedAds;
    const recencySortedAds = ads.sort((ad1, ad2) => {
      const ad1ID = AdEngine.instance.getLastSeen(ad1.adId) || 0;
      const ad2ID = AdEngine.instance.getLastSeen(ad2.adId) || 0;
      return ad2ID - ad1ID;
    });
    const impressionAges = new Map();
    const minLastSeen = AdEngine.instance.getLastSeen(recencySortedAds === null || recencySortedAds === void 0 || (_recencySortedAds = recencySortedAds[recencySortedAds.length - 1]) === null || _recencySortedAds === void 0 ? void 0 : _recencySortedAds.adId);
    const maxLastSeen = AdEngine.instance.getLastSeen(recencySortedAds[0].adId);
    if (maxLastSeen === minLastSeen) {
      recencySortedAds.forEach(ad => {
        impressionAges.set(ad.adId, 1);
      });
    } else {
      recencySortedAds.forEach((ad, index) => {
        const impressionAge = index / recencySortedAds.length;
        impressionAges.set(ad.adId, impressionAge);
      });
    }
    return impressionAges;
  }
  weightedRandomChoice(weights) {
    let cumulativeWeight = 0;
    const randomValue = Math.random();
    for (let i = 0; i < weights.length; i++) {
      cumulativeWeight += weights[i];
      if (randomValue < cumulativeWeight) {
        return i;
      }
    }
    return weights.length - 1;
  }
  selectAdsByWeightedRandomChoice({
    ads: inputAds,
    scores,
    count
  }) {
    const ads = [...inputAds];
    const selectedAds = [];
    while (selectedAds.length < count && ads.length > 0) {
      const totalScore = ads.reduce((acc, ad) => acc + (scores.get(ad.adId) || 0), 0);
      const weights = ads.map(ad => (scores.get(ad.adId) || 0) / totalScore);
      const likelihoods = weights.map(weight => weight / weights.reduce((acc, w) => acc + w, 0));
      const selectedAdIndex = this.weightedRandomChoice(likelihoods);
      selectedAds.push(ads[selectedAdIndex]);
      ads.splice(selectedAdIndex, 1);
    }
    return selectedAds;
  }
}
//# sourceMappingURL=AdSupplier.js.map