<script setup lang="ts">
import moment from "moment";
import { onMounted, onUnmounted } from "vue";
import { Play, Pause } from "@vicons/ionicons5";

const props = defineProps<{ src: string; name: string; playCount: number }>();
const emit = defineEmits<{ (e: "played"): void }>();

let context: AudioContext;
let buffer: AudioBuffer;
let source: AudioBufferSourceNode;

let downloadPercent: string | number = $ref("");
let duration: number = $ref(0);
let currentTime: number = $ref(0);

let playing = $ref(false);

const shouldShowAudio = $computed(() => downloadPercent === 100);

onMounted(() => {
  loadData();
});

onUnmounted(async () => {
  source?.stop();
  await context?.close();
});

function formatTime(seconds: number) {
  return moment.utc(seconds * 1000).format("mm:ss");
}

function loadDogSound(url: string) {
  var request = new XMLHttpRequest();
  request.open("GET", url, true);
  request.responseType = "arraybuffer";

  // Decode asynchronously
  request.onload = () => {
    logger({
      cnl: ["server"],
      lvl: "debug",
      pgu: "AUTO",
      act: "开始下载音频",
    });
    context
      .decodeAudioData(
        <ArrayBuffer>request.response,
        (_buffer: AudioBuffer) => {
          buffer = _buffer;
          duration = Math.floor(buffer.duration);
          downloadPercent = 100;
          logger({
            cnl: ["server"],
            lvl: "debug",
            pgu: "AUTO",
            act: "音频下载完成",
          });
        }
      )
      .catch(() => {
        logger({
          cnl: ["server"],
          lvl: "debug",
          pgu: "AUTO",
          dtl: "error load audio",
        });
      });
  };
  request.onprogress = (e) => {
    downloadPercent = Number((e.loaded / e.total) * 100).toFixed(2);
  };
  request.send();
}

function loadData() {
  context = new AudioContext();

  loadDogSound(props.src);
}

async function play() {
  if (props.playCount <= 0) {
    logger({
      cnl: ["server"],
      lvl: "debug",
      pgu: "AUTO",
      act: "播放音频",
      dtl: "无播放次数",
    });
    return;
  }
  if (playing) {
    logger({
      cnl: ["server"],
      lvl: "debug",
      pgu: "AUTO",
      act: "播放音频",
      dtl: "正在播放，无法暂停",
    });
    return;
  }
  emit("played");
  logger({
    cnl: ["server"],
    lvl: "debug",
    pgu: "AUTO",
    act: "点击播放音频",
  });
  await context.close();

  context = new AudioContext();
  source = context.createBufferSource(); // creates a sound source
  source.buffer = buffer; // tell the source which sound to play
  source.connect(context.destination); // connect the source to the context's destination (the speakers)
  source.start(0); // play the source now
  playing = true;
  currentTime = 0;
  const progress = () => {
    // console.log(context.currentTime, buffer.duration);
    currentTime = Math.floor(context.currentTime);
    if (context.currentTime < buffer.duration) {
      requestAnimationFrame(progress);
    } else if (context.currentTime >= buffer.duration) {
      currentTime = 0;
      requestAnimationFrame(progress);
    }
  };
  requestAnimationFrame(progress);
  // note: on older systems, may have to use deprecated noteOn(time);
  source.onended = () => {
    playing = false;
    currentTime = 0;
    logger({
      cnl: ["server"],
      lvl: "debug",
      pgu: "AUTO",
      act: "播放音频播放结束",
    });
  };
}
</script>

<template>
  <span class="a-container" style="display: inline-flex; align-items: center">
    <span v-show="shouldShowAudio">
      <n-button
        v-if="!playing"
        type="primary"
        :circle="true"
        :disabled="playCount === 0"
        @click="play"
      >
        <NIcon class="tw-ml-1" :component="Play" />
      </n-button>
      <n-button
        v-else
        type="success"
        :circle="true"
        class="pause tw-cursor-not-allowed"
      >
        <NIcon :component="Pause" />
      </n-button>
    </span>
    <span v-show="shouldShowAudio" class="tw-text-red-500 tw-px-1">
      {{ formatTime(currentTime) }} / {{ formatTime(duration) }}
    </span>

    <span v-if="!shouldShowAudio" style="color: blueviolet">
      音频下载中{{ downloadPercent }}%
    </span>
  </span>
</template>
