type CoffeeCup = {
  shots: number;
  hasMilk?: boolean;
  hasSugar?: boolean;
};

*// interface*
interface CoffeeMakerA {
  makeCoffee(shots: number): CoffeeCup;
}

*// Parent Class : CoffeeMaker*
class CoffeeMaker implements CoffeeMakerA {
  private static BEANS_GRANS_PER_SHOT = 7;
  constructor(

		*// Composition 의 방법으로 상속말 Class 멤버변수에 해당 객체를 가져다 쓰는 방법*
    private coffeeBeans: number,
    private milk: MilkFrother,   *// 우유거품기 인터페이스*
    private sugar: SugarProvider *// 설탕제조기 인터페이스*

  ) {
    this.coffeeBeans = coffeeBeans;
  }

  fillCoffeeBeans(beans: number) {
    if (beans < 0) {
      throw new Error('beans not enoughf');
    }
    this.coffeeBeans += beans;
  }

  private grindBeans(shots: number) {
    console.log(`grinding beans for ${shots}`);
    if (this.coffeeBeans < shots * CoffeeMaker.BEANS_GRANS_PER_SHOT) {
      throw new Error('Not enough coffee beans!');
    }
    this.coffeeBeans -= shots * CoffeeMaker.BEANS_GRANS_PER_SHOT;
  }

  private preheat(): void {
    console.log('heating up...🔥');
  }

  private extract(shots: number): CoffeeCup {
    console.log(`Pulling ${shots} shots...☕`);
    return {
      shots: shots,
      hasMilk: false,
    }
  }

  public makeCoffee(shots: number): CoffeeCup { *// public 은 생략 되어 있음*
    this.grindBeans(shots);
    this.preheat();
    const coffee = this.extract(shots);
    const addsugar = this.sugar.addSugar(coffee);
    return this.milk.makeMilk(addsugar);
  }
}

*// interface (우유 거품기)*
interface MilkFrother {
  makeMilk(cup: CoffeeCup): CoffeeCup;
}

*// interface (설탕 제조기)*
interface SugarProvider {
  addSugar(cup: CoffeeCup): CoffeeCup;
}

*// 우유 거품기(1)*
class CheapMilkSteamer implements MilkFrother {
	private steamMilk(): void {
    console.log('Steaming some milk...');
  }

  makeMilk(cup: CoffeeCup): CoffeeCup {
    this.steamMilk();
    return {
      ...cup,
      hasMilk: true,
    }
  }
}

*// 우유 거품기(2)*
class FancyMilkSteamer implements MilkFrother {
	private steamMilk(): void {
    console.log('Steaming some milk...');
  }

  makeMilk(cup: CoffeeCup): CoffeeCup {
    this.steamMilk();
    return {
      ...cup,
      hasMilk: true,
    }
  }
}

*// 설탕 제조기(1)*
class CandySugarMixer implements SugarProvider {
  private getSuger() {
    console.log('Gettin some sugar from candy');
    return true;
  }

  addSugar(cup: CoffeeCup): CoffeeCup {
    const sugar = this.getSuger();
    return {
      ...cup,
      hasSugar: sugar,
    }
  }
}

*// 설탕 제조기(2)*
class SugarMixer implements SugarProvider {
  private getSuger() {
    console.log('Gettin some sugar from candy');
    return true;
  }

  addSugar(cup: CoffeeCup): CoffeeCup {
    const sugar = this.getSuger();
    return {
      ...cup,
      hasSugar: sugar,
    }
  }
}

*// 호출 유형 & 방법 예시 기억해 두기 ★★★*
*// Milk*
const cheapMilkMaker = new CheapMilkSteamer();
const fancyMilkMaker = new FancyMilkSteamer();
*// Sugar*
const candySugar = new CandySugarMixer();
const sugar      = new SugarMixer();

*// Machine*
const sweetLatteMachine = new CoffeeMaker(12, cheapMilkMaker, candySugar);
const coldLatteMachine  = new CoffeeMaker(12, fancyMilkMaker, sugar );
const seetLatteMachine2 = new CoffeeMaker(12, cheapMilkMaker, candySugar);