import getRealPath from 'uni-platform/helpers/get-real-path'

/**
 * 可以批量设置的监听事件
 */
const innerAudioContextEventNames = ['onCanplay', 'onPlay', 'onPause', 'onStop', 'onEnded', 'onTimeUpdate', 'onError', 'onWaiting', 'onSeeking', 'onSeeked']

const innerAudioContextOffEventNames = ['offCanplay', 'offPlay', 'offPause', 'offStop', 'offEnded', 'offTimeUpdate', 'offError', 'offWaiting', 'offSeeking', 'offSeeked']

/**
 * 音频上下文对象
 */
class InnerAudioContext {
  /**
   * 原始音频对象
   */
  _audio
  /**
   * 是否暂停中
   */
  _stoping
  /**
   * 开始时间
   */
  startTime
  /**
   * 事件监听
   */
  _events
  /**
   * 音频地址
   */
  _src
  /**
   * 音频上下文初始化
   */
  constructor () {
    var audio = this._audio = new Audio()
    this._stoping = false
    // 和audio对象同名同效果的属性
    var propertys = ['src', 'autoplay', 'loop', 'duration', 'currentTime', 'paused', 'volume']
    propertys.forEach((property) => {
      Object.defineProperty(this, property, {
        set: property === 'src' ? (src) => {
          audio.src = getRealPath(src)
          this._src = src
          return src
        } : (val) => {
          audio[property] = val
          return val
        },
        get: property === 'src' ? () => {
          return this._src
        } : () => {
          return audio[property]
        }
      })
    })
    this.startTime = 0
    Object.defineProperty(this, 'obeyMuteSwitch', {
      set (val) {
        return false
      },
      get () {
        return false
      }
    })
    Object.defineProperty(this, 'buffered', {
      get () {
        var buffered = audio.buffered
        if (buffered.length) {
          return buffered.end(buffered.length - 1)
        } else {
          return 0
        }
      }
    })
    // 初始化事件监听列表
    this._events = {}
    innerAudioContextEventNames.forEach(eventName => {
      this._events[eventName] = []
    })
    audio.addEventListener('loadedmetadata', () => {
      var startTime = Number(this.startTime) || 0
      if (startTime > 0) {
        audio.currentTime = startTime
      }
    })
    // 和audio对象同名同效果的事件
    var eventNames = ['canplay', 'play', 'pause', 'ended', 'timeUpdate', 'error', 'waiting', 'seeking', 'seeked']
    var stopEventNames = ['pause', 'seeking', 'seeked', 'timeUpdate']
    eventNames.forEach(eventName => {
      audio.addEventListener(eventName.toLowerCase(), () => {
        // stop事件过滤
        if (this._stoping && stopEventNames.indexOf(eventName) >= 0) {
          return
        }
        this._events[`on${eventName.substr(0, 1).toUpperCase()}${eventName.substr(1)}`].forEach((callback) => {
          callback()
        })
      }, false)
    })
  }

  /**
   * 播放
   */
  play () {
    this._stoping = false
    this._audio.play()
  }

  /**
   * 暂停
   */
  pause () {
    this._audio.pause()
  }

  /**
   * 停止
   */
  stop () {
    this._stoping = true
    this._audio.pause()
    this._audio.currentTime = 0
    this._events.onStop.forEach((callback) => {
      callback()
    })
  }

  /**
   * 跳转到
   * @param {number} position
   */
  seek (position) {
    this._stoping = false
    position = Number(position)
    if (typeof position === 'number' && !isNaN(position)) {
      this._audio.currentTime = position
    }
  }

  /**
   * 销毁
   */
  destroy () {
    this.stop()
  }
}

// 批量设置音频上下文事件监听方法
innerAudioContextEventNames.forEach((eventName) => {
  InnerAudioContext.prototype[eventName] = function (callback) {
    if (typeof callback === 'function') {
      this._events[eventName].push(callback)
    }
  }
})

// 批量设置音频上下文事件取消监听方法
innerAudioContextOffEventNames.forEach((eventName) => {
  InnerAudioContext.prototype[eventName] = function (callback) {
    var handle = this._events[eventName.replace('off', 'on')]
    var index = handle.indexOf(callback)
    if (index >= 0) {
      handle.splice(index, 1)
    }
  }
})

/**
 * 创建音频上下文
 */
export function createInnerAudioContext () {
  return new InnerAudioContext()
}
