/**
 * 音频合成节拍器
 */
import Crunker from './crunker'
import tickMp3 from './tick.mp3'
import tockMp3 from './tock.mp3'
import { getUploadSign, onOnlyFileUpload } from '@/utils/oss-file-upload'
import { ref } from 'vue'

const crunker = new Crunker()

type musicSheetType = {
  audioFileUrl: string
  audioBeatMixUrl: null | string
  solmizationFileUrl: null | string
  solmizationBeatUrl: null | string
}

type taskAudioType = {
  obj: musicSheetType
  type: 'audioFileUrl' | 'solmizationFileUrl'
  audioBuff?: AudioBuffer
}[]

// 节拍器数据
export const beatState = {
  times: [] as number[][],
  totalIndex: ref(0), // 总共需要处理的音频个数
  currentIndex: ref(0) // 当前处理了多少条数据
}

// 节拍器音源
let tickMp3Buff: null | AudioBuffer = null
let tockMp3Buff: null | AudioBuffer = null

export default async function audioMergeBeats({
  musicSheetAccompanimentList,
  musicSheetSoundList
}: {
  musicSheetAccompanimentList: musicSheetType[]
  musicSheetSoundList: musicSheetType[]
}) {
  if (!beatState.times.length) return
  try {
    if (musicSheetSoundList.length + musicSheetAccompanimentList.length > 0) {
      // 扁平化数据 生成任务队列
      const taskAudio: taskAudioType = []
      ;[...musicSheetSoundList, ...musicSheetAccompanimentList].map((item) => {
        taskAudio.push({
          obj: item,
          type: 'audioFileUrl'
        })
        item.solmizationFileUrl && // 有唱名加上唱名
          taskAudio.push({
            obj: item,
            type: 'solmizationFileUrl'
          })
      })
      beatState.totalIndex.value = taskAudio.length
      /* 加载节拍器 */
      if (!tickMp3Buff || !tockMp3Buff) {
        const [tickMp3Bf, tockMp3Bf] = await crunker.fetchAudio(tickMp3, tockMp3)
        tickMp3Buff = tickMp3Bf
        tockMp3Buff = tockMp3Bf
      }
      /* 加上所有的音频文件 */
      await Promise.all(
        taskAudio.map(async (item) => {
          const [audioBuff] = await crunker.fetchAudio(item.obj[item.type]!)
          item.audioBuff = audioBuff
        })
      )
      /* 异步上传 */
      await new Promise((res) => {
        /* 合成音源 */
        taskAudio.map(async (item) => {
          const audioBlob = mergeBeats(item.audioBuff!)
          const url = await uploadFile(audioBlob)
          item.obj[item.type == 'audioFileUrl' ? 'audioBeatMixUrl' : 'solmizationBeatUrl'] = url
          beatState.currentIndex.value++
          if (beatState.currentIndex.value >= beatState.totalIndex.value) {
            res(null)
          }
        })
      })
    }
  } catch (err) {
    console.log('处理音频合成上传失败', err)
  }
  // 清空数据
  beatState.currentIndex.value = 0
  beatState.totalIndex.value = 0
  beatState.times = []
}

// 根据buffer合成音源返回blob
function mergeBeats(audioBuff: AudioBuffer) {
  // 计算音频空白时间
  const silenceDuration = crunker.calculateSilenceDuration(audioBuff)
  const beats: AudioBuffer[] = []
  const currentTimes: number[] = []
  beatState.times.map((items) => {
    items.map((time, index) => {
      beats.push(index === 0 ? tickMp3Buff! : tockMp3Buff!)
      currentTimes.push(time + silenceDuration)
    })
  })
  //合并
  const mergeAudioBuff = crunker.mergeAudioBuffers([audioBuff, ...beats], [0, ...currentTimes])
  //转为 blob
  return crunker.audioBuffToBlob(mergeAudioBuff)
}

/**
 * 上传文件
 */
async function uploadFile(audioBlob: Blob) {
  const filename = `${new Date().getTime()}.mp3`
  const { data } = await getUploadSign({
    filename,
    bucketName: 'cloud-coach',
    postData: {
      filename,
      acl: 'public-read',
      key: filename,
      unknowValueField: []
    }
  })
  const url = await onOnlyFileUpload('', {
    KSSAccessKeyId: data.KSSAccessKeyId,
    acl: 'public-read',
    file: audioBlob,
    key: filename,
    name: filename,
    policy: data.policy,
    signature: data.signature
  })
  return url
}
