import { EventEmitter } from '@angular/core';

export class AudioDelegate {
  audioObj = new Audio();
  public audioPlayTimestamp = new EventEmitter();
  public audioDataLoaded = new EventEmitter();
  public audioPlayBarPosition = new EventEmitter();
  public audioPlayEnd = new EventEmitter();
  syncAudioCurrentTimeId: number = null;
  private arrayBuffer = null;
  formatter = new Intl.NumberFormat('en', {
    minimumIntegerDigits: 2,
    minimumFractionDigits: 3,
    maximumFractionDigits: 3,
    useGrouping: false,
  });
  constructor() {
    this.audioObj.onloadeddata = this.onAudioDataLoaded.bind(this);
    this.audioObj.onplay = this.onAudioPlay.bind(this);
    this.audioObj.onpause = this.onAudioPause.bind(this);
    this.audioObj.ontimeupdate = this.onAudioTimeUpdate.bind(this);
    this.audioObj.onratechange = this.onAudioRateChange.bind(this);
    this.audioObj.onended = this.onAudioEnded.bind(this);
    this.audioObj.onerror = () => {
    };
  }
  set playbackRate(val) {
    this.audioObj.playbackRate = val;
  }

  set src(val) {
    this.audioObj.src = val;
  }
  get src() {
    return this.audioObj.src;
  }
  convertTagToTime(tag) {
    tag = tag.replace('[', '');
    tag = tag.replace(']', '');
    const parts = tag.split(':');
    let h = 0;
    let m = 0;
    let s = 0;
    if (parts.length === 3) {
      h = parseInt(parts[0], 10);
      m = parseInt(parts[1], 10);
      s = parseInt(parts[2], 10);
    } else if (parts.length === 2) {
      m = parseInt(parts[0], 10);
      s = parseFloat(parts[1] );
    }

    return h * 60 * 60 + m * 60 + s;
  }
  convertTimeToTag(time, withBracket = true): string {
    if (time === undefined) {
      return '';
    }
    const hh = Math.floor(time / 60 / 60)
      .toString()
      .padStart(2, '0');
    const mm = Math.floor(time / 60)
      .toString()
      .padStart(2, '0');
    const ss = this.formatter.format(time % 60);

    return withBracket ? `[${hh}:${mm}:${ss}]` : `${hh}:${mm}:${ss}`;
  }
  setSource(ab) {
    this.arrayBuffer = ab;
    const blob = new Blob([ab], { type: 'audio/wav' });
    this.audioObj.src = URL.createObjectURL(blob);
  }
  getDataBuffer() {
    return this.arrayBuffer;
  }

  getBufferClip(start, end) {
    return this.arrayBuffer.slice(start * this.arrayBuffer.length, end * this.arrayBuffer.length);
  }
  load() {
    this.audioObj.load();
  }
  syncAudioCurrentTime() {
    this.audioPlayTimestamp.emit({
      timeFormat: this.convertTimeToTag(this.audioObj.currentTime, false),
      time: this.audioObj.currentTime
    });
    this.syncAudioCurrentTimeId = requestAnimationFrame(() => {
      this.syncAudioCurrentTime();
    });
  }
  onAudioDataLoaded(evt) {
    console.log('onAudioDataLoaded', evt);
    this.audioDataLoaded.emit(this.arrayBuffer);
  }
  onAudioPlay() {
    this.syncAudioCurrentTimeId = requestAnimationFrame(() => {
      this.syncAudioCurrentTime();
    });
    console.log('onAudioPlay');
  }
  onAudioPause() {
    console.log('onAudioPause');
    cancelAnimationFrame(this.syncAudioCurrentTimeId);
  }
  onAudioEnded() {
    console.log('onAudioEnded');
    this.audioPlayEnd.emit()
    cancelAnimationFrame(this.syncAudioCurrentTimeId);
  }
  onAudioTimeUpdate() {
    // console.log('onAudioTimeUpdate', this.convertTimeToTag(this.audioObj.currentTime));
    // this.audioPlayTimestamp.emit(this.convertTimeToTag(this.audioObj.currentTime));
  }
  onAudioRateChange() {
    console.log('onAudioRateChange');
  }
  get isPlaying() {
    return !!(this.audioObj.currentTime > 0
      && !this.audioObj.paused
      && !this.audioObj.ended
      && this.audioObj.readyState > 2);
  }

  currentTimeFormatted(time?) {
    let t = this.audioObj.currentTime;
    if (typeof time !== 'undefined') {
      t = time;
    }
    return this.convertTimeToTag(t);
  }

  get currentTime() {
    return this.audioObj.currentTime;
  }
  set currentTime(val) {
    this.audioPlayBarPosition.emit({
      time: val
    });
    this.audioObj.currentTime = val;
  }
  get duration() {
    return this.audioObj.duration;
  }
  get durationFormatted() {
    return this.convertTimeToTag(this.audioObj.duration, false);
  }
  get currentSrc() {
    return this.audioObj.currentSrc;
  }
  pause() {
    this.audioObj.pause();
  }
  async play() {
    return this.audioObj.play();
  }
}
