const EventEmitter = require("events").EventEmitter;

class Pizza extends EventEmitter {
  constructor(size = 1) {
    super();
    this.ovenTime = this._ovenTime(size);
    this.maxIngredients = this._maxIngredients(size);
    this.ingredients = [];
    this.timeToReleasePizza = 5;
  }

  /**
   * Static function that returns size types
   */
  static sizes() {
    return {
      small: 1,
      medium: 2,
      familiar: 3
    };
  }

  /**
   * Max pizza ingredients by size
   * @param {Number} size
   * @returns {Number}
   */
  _maxIngredients(size) {
    return size * 3;
  }

  /**
   * Oven time by size
   * @param {Number} size
   * @returns {Number}
   */
  _ovenTime(size) {
    return 5 + size * 2;
  }

  /**
   * Checks if max number of ingredients was reached
   * @returns {Boolean}
   */
  _isMaxIngredientsReached() {
    return this.ingredients.length === this.maxIngredients;
  }

  /**
   * Adds and ingredient to pizza if max was
   * not reached and emits events in both cases
   * @param {String} ingredient
   * @returns {Pizza}
   */
  add(ingredient) {
    if (!this._isMaxIngredientsReached()) {
      this.ingredients.push(ingredient);
      this.emit("ingredientAdded", ingredient);
    } else {
      this.emit("maxIngredientsReached");
    }
    return this;
  }

  /**
   * Removes and ingredient from the pizza if founf
   * and emits events in both cases
   * @param {String} ingredient
   * @returns {Pizza}
   */
  remove(ingredient) {
    const ingredientToRemove = this.ingredients.indexOf(ingredient);
    if (ingredientToRemove !== -1) {
      this.ingredients.splice(ingredientToRemove, 1);
      this.emit("ingredientRemoved", ingredient);
    } else {
      this.emit("errorRemovingIngredient", ingredient);
    }
    return this;
  }

  /**
   * It starts the timer once the oven time is passed,
   * the pizza has to be released (clearing interval)
   * in an specific amount of time to avoid charring
   * @returns {Pizza}
   */
  cook() {
    this.emit("cookStarted");
    setTimeout(() => {
      const releasePizza = setTimeout(() => {
        this.emit("charredPizza");
      }, this.timeToReleasePizza);
      this.emit("cookFinished", releasePizza);
    }, this.ovenTime);

    return this;
  }
}

const createMediumPizza = () => {
  const pizza = new Pizza(Pizza.sizes().medium);
  pizza
    .on("ingredientAdded", ing => console.log(`${ing} added`))
    .on("maxIngredientsReached", ing =>
      console.log(`Max ingredients (${pizza.maxIngredients}) reached`)
    )
    .on("ingredientRemoved", ing => console.log(`${ing} removed`))
    .on("errorRemovingIngredient", ing =>
      console.log(`Can not remove ${ing} because is not in the pizza`)
    )
    .on("cookStarted", () => console.log("Pizza is in the oven."))
    .on("cookFinished", release => {
      console.log(`Pizza is ready to release.`);
      clearTimeout(release);
      console.info("Pizza was released!");
    })
    .add("Tomato")
    .add("Mushrooms")
    .add("Scarmoza")
    .add("Bone")
    .remove("Bone")
    .add("Pepper")
    .remove("Peper")
    .add("Onion")
    .add("Pepperoni")
    .add("Oregano")
    .cook();
};

const createSmallPizza = () => {
  const pizzaSmall = new Pizza(Pizza.sizes().small);
  pizzaSmall
    .on("cookFinished", () => {
      console.log(`PizzaSmall is ready to release.`);
      // no clearing interval of release
    })
    .on("cookStarted", () => console.log("PizzaSmall is in the oven"))
    .on("charredPizza", () =>
      console.error("OOPS! The PizzaSmall is charred...")
    )
    .add("mozzarella")
    .add("Meat")
    .cook();
};

//createMediumPizza();
createSmallPizza();