import { count } from "console";

/**
 * Finds the highest quantity that can be sold of an item adjusted to its `multipleQuantity`
 * @param stock item stock
 * @param maxQuantity maximum quantity of this item that can be added
 * @param multipleQuantity `multipleQuantity` for the item
 * @returns the highest quantity of the item that can be sold
 */
export const getMaximumValue = (
  stock: number,
  maxQuantity: number,
  multipleQuantity: number
): number => {
  const maxValue = Math.min(stock, maxQuantity);
  const maxQuantityTimes = Math.floor(maxValue / multipleQuantity) ?? 1;
  const maxStockMultipleQuantity = maxQuantityTimes * multipleQuantity;
  return maxStockMultipleQuantity;
};
/**
 * Find the `multipleQuantity` closest to `quantity`
 * @param quantity amount you want to add
 * @param multipleQuantity multipleQuantity of this item
 * @param stock item stock
 * @returns quantity that complies with the `multiple Quantity`
 */
export const roundToMultipleQuantity = (
  quantity: number,
  multipleQuantity: number,
  stock: number
) => {
  const roundNumber =
    Math.round(quantity / multipleQuantity) * multipleQuantity;
  const roundStock = Math.floor(stock / multipleQuantity) * multipleQuantity;
  return stock < roundNumber ? roundStock : roundNumber;
};

export const getDiscount = (regularPrice: number, discountedPrice: number) =>
  ((regularPrice - discountedPrice) / regularPrice) * 100;

const min = (a?: number, b?: number): number | undefined => {
  if (a === undefined) {
    return b;
  }
  if (b === undefined) {
    return a;
  }
  return a < b ? a : b;
};

class MaxCounter {
  private _max?: number;
  private _count = 0;
  private _counter?: MaxCounter;

  constructor(max?: number | null, counter?: MaxCounter) {
    this._max = max ?? undefined;
    this._counter = counter;
  }

  get max(): number | undefined {
    return min(
      this._max ? this._max - this._count : undefined,
      this._counter?.max
    );
  }

  get maxAndAdd(): number | undefined {
    const maxQuantity = this.max;
    this.add(maxQuantity || 0);
    return maxQuantity;
  }

  set counter(counter: MaxCounter) {
    this._counter = counter;
  }

  add(count: number) {
    this._count += count;
    this._counter?.add(count);
  }
}

export class MaxQuantityHelper {
  private readonly _quantity: MaxCounter;
  private readonly _discounted: MaxCounter;
  private readonly _scales = new Map();

  constructor(
    productMaxQuantity?: number | null,
    discountedMaximumQuantity?: number | null
  ) {
    this._quantity = new MaxCounter(productMaxQuantity);
    this._discounted = new MaxCounter(
      discountedMaximumQuantity,
      this._quantity
    );
  }

  private scaleMaxQuantity(counter: MaxCounter, startQuantity = 1, endQuantity?: number) {
    if (endQuantity) {
      const scale = this._scales.get(startQuantity);
      if (scale) {
        scale.counter = counter;
        counter = scale;
      } else {
        counter = new MaxCounter(endQuantity - startQuantity + 1, counter);
        this._scales.set(startQuantity, counter);
      }
    }
    return counter.maxAndAdd;
  }

  public maxQuantity(
    startQuantity = 1,
    endQuantity?: number
  ): number | undefined {
    return this.scaleMaxQuantity(this._quantity, startQuantity, endQuantity);
  }

  public discountedMaxQuantity(
    startQuantity = 1,
    endQuantity?: number
  ): number | undefined {
    return this.scaleMaxQuantity(this._discounted, startQuantity, endQuantity);
  }
}
