/* eslint-disable no-unreachable */
import Event from 'eventemitter3';
import { CSSProperties } from 'react';

import { eAudioCoreEvts } from './AudioCore.events';

// 音频状态
interface iAudioStatus {
  currentTime: number; // 当前时间
  playbackRate: number; // 播放速率
  volume: number; // 音量
  muted: boolean; // 是否静音
  duration: number; // 总时长
}

// 初始化参数
interface iAudioCoreParams {
  audioSrc: string; // 音频链接
  autoPlay?: boolean; // 是否自动播放
  audioStatus?: iAudioStatus; // 初始化参数
  audioEleStyles?: CSSProperties; // audio 元素样式
}

// 音频核心
class AudioCore extends Event {
  private audioCoreParams: iAudioCoreParams; // 初始化参数
  private audioElement!: HTMLAudioElement; // audio 元素
  private audioIsPlaying = false; // 是否正在播放
  // 音频状态
  private audioStatus: iAudioStatus = {
    currentTime: 0, // 当前时间
    playbackRate: 1, // 播放速率
    volume: 0.5, // 音量
    muted: false, // 是否静音
    duration: 0, // 总时长
  };
  // 默认音频样式
  private audioEleStyles: CSSProperties = {
    width: 0,
    height: 0,
    display: 'none',
  };

  // 状态同步
  get isPlaying() {
    return this.audioIsPlaying;
  }
  get currentTime() {
    return this.audioStatus.currentTime;
  }
  set currentTime(time: number) {
    if (this.audioStatus.currentTime === time) return;
    this.audioStatus.currentTime = time;
    this.audioElement.currentTime = time;
  }
  get playbackRate() {
    return this.audioStatus.playbackRate;
  }
  set playbackRate(rate: number) {
    if (this.audioStatus.playbackRate === rate) return;
    this.audioStatus.playbackRate = rate;
    this.audioElement.playbackRate = rate;
  }
  get volume() {
    return this.audioStatus.volume;
  }
  set volume(volume: number) {
    if (this.audioStatus.volume === volume) return;
    this.audioStatus.volume = volume;
    this.audioElement.volume = volume;
  }
  get muted() {
    return this.audioStatus.muted;
  }
  set muted(muted: boolean) {
    if (this.audioStatus.muted === muted) return;
    this.audioStatus.muted = muted;
    this.audioElement.muted = muted;
  }
  get duration() {
    return this.audioStatus.duration;
  }

  constructor(params: iAudioCoreParams) {
    super();
    this.audioCoreParams = params;
    this.audioStatus = Object.assign({}, this.audioStatus, params.audioStatus);
    this.audioEleStyles = Object.assign(
      {},
      this.audioEleStyles,
      params.audioEleStyles,
    );
    this.init();
  }

  // 更改音频 SRC
  // changeAudioSrc = () => {};

  // 销毁元素
  destroy = () => {
    this.offEventListener();
    if (document.body.contains(this.audioElement)) {
      document.body.removeChild(this.audioElement);
    }
  };

  // 播放控制
  async play() {
    return this.audioElement
      .play()
      .then(() => {
        this.audioIsPlaying = true;
        return true;
      })
      .catch((e) => {
        console.error('AudioCore:Play:Error', e);
        return false;
      });
  }
  async pause() {
    this.audioElement.pause();
    this.audioIsPlaying = false;
  }

  getAudioElement() {
    return this.audioElement;
  }

  // 音频初始化
  private init() {
    const { audioSrc } = this.audioCoreParams;
    // 初始化 Audio、添加事件监听、挂载元素
    const audioElement = document.createElement('audio');
    this.audioElement = audioElement;
    audioElement.src = audioSrc;
    audioElement.crossOrigin = 'anonymous';

    const { audioEleStyles, audioStatus } = this;
    // 音频样式设置
    Object.keys(audioEleStyles).forEach((key) => {
      audioElement.style[key] = audioEleStyles[key];
    });
    // 音频状态同步
    const syncToMediaElementPropKeys = [
      'currentTime',
      'playbackRate',
      'volume',
      'muted',
    ];
    Object.keys(audioStatus).forEach((key) => {
      if (syncToMediaElementPropKeys.includes(key)) {
        audioElement[key] = audioStatus[key];
      }
    });

    audioElement.load();
    this.addEventListener();
    // 挂载元素
    console.log('audio audioElement init');
    document.body.appendChild(audioElement);
  }
  // 事件监听器
  private addEventListener() {
    this.audioElement.addEventListener('durationchange', this.onDurationChange);
    this.audioElement.addEventListener('timeupdate', this.onTimeUpdate);
    this.audioElement.addEventListener('canplay', this.onCanPlay);
    this.audioElement.addEventListener('ended', this.onEnded);
    this.audioElement.addEventListener('play', this.onPlay);
    this.audioElement.addEventListener('pause', this.onPause);
    this.audioElement.addEventListener('volumechange', this.onVolumeChange);
    this.audioElement.addEventListener('ratechange', this.onRateChange);
    this.audioElement.addEventListener('error', this.onError);
  }
  private offEventListener() {
    this.audioElement.removeEventListener(
      'durationchange',
      this.onDurationChange,
    );
    this.audioElement.removeEventListener('timeupdate', this.onTimeUpdate);
    this.audioElement.removeEventListener('canplay', this.onCanPlay);
    this.audioElement.removeEventListener('ended', this.onEnded);
    this.audioElement.removeEventListener('play', this.onPlay);
    this.audioElement.removeEventListener('pause', this.onPause);
    this.audioElement.removeEventListener('volumechange', this.onVolumeChange);
    this.audioElement.removeEventListener('ratechange', this.onRateChange);
  }
  // 内部事件监听，对外透出
  private onDurationChange = () => {
    this.audioStatus.duration = this.audioElement.duration;
    this.emit(eAudioCoreEvts.durationchange, this.audioStatus.duration);
  };
  private onTimeUpdate = () => {
    this.audioStatus.currentTime = this.audioElement.currentTime;
    this.emit(eAudioCoreEvts.timeupdate, this.audioStatus.currentTime);
  };
  private onCanPlay = () => {
    this.emit(eAudioCoreEvts.canplay);
    if (this.audioCoreParams.autoPlay) {
      this.play();
    }
  };
  private onPlay = () => {
    this.audioIsPlaying = true;
    this.emit(eAudioCoreEvts.play);
  };
  private onPause = () => {
    this.audioIsPlaying = false;
    this.emit(eAudioCoreEvts.pause);
  };
  private onEnded = () => {
    this.audioIsPlaying = false;
    this.emit(eAudioCoreEvts.ended);
  };
  private onVolumeChange = () => {
    // 1.静音状态改变
    if (this.audioStatus.muted !== this.audioElement.muted) {
      this.audioStatus.muted = this.audioElement.muted;
      this.emit(eAudioCoreEvts.muted, this.audioStatus.muted);
      return;
    }
    // 2.音量改变
    this.audioStatus.volume = this.audioElement.volume;
    this.emit(eAudioCoreEvts.volumechange, this.audioStatus.volume);
  };
  private onRateChange = () => {
    this.audioStatus.playbackRate = this.audioElement.playbackRate;
    this.emit(eAudioCoreEvts.ratechange, this.audioStatus.playbackRate);
  };
  private onError = (e) => {
    this.emit(eAudioCoreEvts.error, e);
  };
}

export { AudioCore };
export type { iAudioStatus, iAudioCoreParams };
