import EventEmitter from "eventemitter3";

export class NeosAudioContext extends EventEmitter<AudioScheduledSourceNodeEventMap> {
  private _musicAudioContext = new AudioContext();
  private _gainNode = this._musicAudioContext.createGain();

  constructor(volume = 1) {
    super();
    this._gainNode.gain.value = volume;
  }

  public get musicAudioContext() {
    return this._musicAudioContext;
  }

  public get state() {
    return this._musicAudioContext.state;
  }

  public async play(audio: ArrayBuffer) {
    const source = this._musicAudioContext.createBufferSource();
    const buffer = await this._musicAudioContext.decodeAudioData(audio);
    source.buffer = buffer;

    source.connect(this._gainNode).connect(this._musicAudioContext.destination);
    source.start();
    if (this.state === "suspended") {
      const autoPlay = () => {
        document.removeEventListener("click", autoPlay);
        this.resume();
      };
      document.addEventListener("click", autoPlay);
    }
    const Ended = () => {
      source.removeEventListener("ended", Ended);
      this.emit("ended");
    };
    source.addEventListener("ended", Ended);
  }

  public async resume() {
    if (this.state !== "suspended") return;
    return this._musicAudioContext.resume();
  }

  public async suspend() {
    if (this.state !== "running") return;
    return this._musicAudioContext.suspend();
  }

  public close() {
    if (this._musicAudioContext.state === "closed") return;
    return this._musicAudioContext.close();
  }

  public updateVolume(volume: number) {
    this._gainNode.gain.value = volume;
  }
}
