<template>
  <div class="audio-wrap" data-weiling-mobile-ui-wl-audio>
    <audio
      :src="src"
      v-bind="$attrs"
      :loop="loop"
      ref="audioRef"
      preload="metadata"
      @loadedmetadata="loadedmetadata"
      @ended="ended"
      @pause="pause"
      @play="play"
      @playing="playing"
      @waiting="waiting"
      @timeupdate="timeupdate"
    >
      Sorry, Your browser does not support the <code>audio</code> element.
    </audio>
    <div class="audio-controls" ref="audioControlsRef">
      <div class="audio">
        <AudioBackground :lineNumber="lineNumber" :isPlaying="isPlaying" />
        <template v-if="needPlaybackRate">
          <div class="playback-rate" @click.stop="onChangeRate">
            {{ rate }}x
          </div>
        </template>
        <div class="step" @click.stop="onBack">
          <div class="forward">
            <p>{{ stepSecond }}</p>
          </div>
        </div>
        <div class="play" @click.stop="onClick">
          <WlSvgIcon
            type="videoFill"
            width="24"
            height="24"
            color="#1c9fff"
            v-show="!isPlaying"
          />
          <WlSvgIcon
            type="pause"
            width="24"
            height="24"
            color="#1c9fff"
            v-show="isPlaying"
          />
        </div>
        <div class="step" @click.stop="onForward">
          <div class="back">
            <p>{{ stepSecond }}</p>
          </div>
        </div>
      </div>
      <div class="speed-progress">
        <div class="played-process" :style="`width: ${played_rate}`"></div>
        <div class="point" :style="`left: ${played_rate}`"></div>
      </div>
      <div class="time">
        <p>{{ formatSecond(currentTime) }}</p>
        <p>{{ formatSecond(duration) }}</p>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
/*
 * @Author: Liao.xiuli
 * @Date: 2021-09-18 11:18:59
 * @Last Modified by: Liao.xiuli
 * @Last Modified time: 2022-08-20 12:48:31
 */
export default {
  name: "WlAudio",
};
</script>

<script setup lang="ts">
import WlSvgIcon from "@mobileUI/components/WlSvgIcon/src/index.vue";
import { computed, ref, onMounted, watch } from "vue";
import AudioBackground from "./components/AudioBackground/index.vue";
type Props = {
  src?: string;
  loop?: boolean;
  stepSecond?: number;
  defaultTime?: number;
  needPlaybackRate?: boolean;
  playbackRateArr?: number[];
  videoDuration?: number;
};
const props = withDefaults(defineProps<Props>(), {
  src: "",
  loop: false,
  stepSecond: 5,
  defaultTime: 0,
  videoDuration: 0,
  needPlaybackRate: false,
  playbackRateArr: () => [0.25, 0.5, 1, 1.25, 1.5, 2],
});

const emit = defineEmits<{
  (e: "onError", val: ErrorEvent);
  (e: "onChangeRate", val: number);
  (e: "onLoadedmetadata", val: HTMLElement);
  (e: "onEnded");
  (e: "onPause");
  (e: "onPlay");
  (e: "onPlaying");
  (e: "onWaiting");
  (e: "onEnded");
  (e: "onForward");
  (e: "onBack");
}>();

const duration = ref(0);
const currentTime = ref(0);
const isPlaying = ref(false);
const rate = ref(1);
const lineNumber = ref(10);
const audioRef = ref(null);
const audioControlsRef = ref(null);

const played_rate = computed(() => {
  if (currentTime.value > duration.value) {
    return "100%";
  }
  if (duration.value === 0) return "0%";
  return (currentTime.value / duration.value) * 100 + "%";
});

const formatSecond = computed(() => {
  return function (seconds) {
    seconds = parseInt(seconds);
    if (Number.isNaN(seconds) || !Number.isSafeInteger(seconds)) {
      return "00:00";
    } else {
      const hour = Math.floor(seconds / 3600);
      const mintue =  Math.floor((seconds - hour * 3600) / 60);
      const second = seconds - mintue * 60 - hour * 3600;
      if (hour !== 0) {
        return `${hour}:${mintue < 10 ? "0" + mintue : mintue}:${
          second < 10 ? "0" + second : second
        }`;
      } else {
        return `${mintue < 10 ? "0" + mintue : mintue}:${
          second < 10 ? "0" + second : second
        }`;
      }
    }
  };
});
watch(
  () => props.defaultTime,
  (val) => {
    if (props.defaultTime < 0) {
      currentTime.value = 0;
    } else {
      currentTime.value = props.defaultTime;
    }
    if (isPlaying.value) {
      audioRef.value.currentTime = currentTime.value;
    }
  }
);

onMounted(() => {
  const width = audioControlsRef.value.clientWidth;
  lineNumber.value = Math.ceil(width / 20);
  audioRef.value.addEventListener("onerror", (err) => {
    emit("onError", err);
  });
});

const loadedmetadata = () => {
  duration.value = audioRef.value?.duration;
  if (currentTime.value > duration.value) {
    currentTime.value = duration.value;
  }
  emit("onLoadedmetadata", audioRef.value);
};

const ended = () => {
  isPlaying.value = false;
  emit("onEnded");
};

const pause = () => emit("onPause");

const play = () => emit("onPlay");

const playing = () => emit("onPlaying");

const waiting = () => emit("onWaiting");

const timeupdate = () => {
  currentTime.value = audioRef.value?.currentTime;
};
const onClick = () => {
  if (!isPlaying.value) {
    if (currentTime.value >= duration.value) {
      currentTime.value = 0;
    }
    audioRef.value.currentTime = currentTime.value;
    audioRef.value.play();
  } else {
    audioRef.value.pause();
  }
  isPlaying.value = !isPlaying.value;
};

const onForward = () => {
  if (currentTime.value + props.stepSecond > duration.value) {
    currentTime.value = duration.value;
  } else {
    audioRef.value.currentTime = currentTime.value + props.stepSecond;
  }
  emit("onForward");
};

const onBack = () => {
  if (currentTime.value - props.stepSecond <= 0) {
    audioRef.value.currentTime = 0;
  } else {
    audioRef.value.currentTime = currentTime.value - props.stepSecond;
  }
  emit("onBack");
};

const onChangeRate = () => {
  let index = props.playbackRateArr.findIndex((ele) => ele === rate.value);
  index = (index + 1) % props.playbackRateArr.length;
  rate.value = props.playbackRateArr[index];
  audioRef.value.playbackRate = rate.value;
  emit("onChangeRate", rate.value);
};

const onChangeTime = (time) => {
  time = parseInt(time);
  if (time > duration.value) {
    audioRef.value.currentTime = duration.value;
  } else {
    audioRef.value.currentTime = time;
  }
};
watch(
  () => props.videoDuration,
  (val) => {
    if (Number(val) !== 0 && duration.value === 0) {
      duration.value = Number(val);
    }
  },
  {
    immediate: true,
  }
);
defineExpose({
  onChangeTime,
});
</script>

<style lang="scss">
.audio-wrap[data-weiling-mobile-ui-wl-audio] {
  @keyframes audio-play-ani {
    10% {
      height: j(8);
    }

    20% {
      height: j(20);
    }

    30% {
      height: j(28);
    }

    40% {
      height: j(16);
    }

    50% {
      height: j(16);
    }

    60% {
      height: j(4);
    }

    70% {
      height: j(8);
    }

    80% {
      height: j(16);
    }

    90% {
      height: j(12);
    }

    100% {
      height: j(4);
    }
  }

  .audio-controls {
    background: #ffffff;
    border-radius: j(8);
    padding: j(8);
    width: 100%;
    height: 100%;
    box-sizing: border-box;

    .audio {
      background-size: auto j(28);
      height: j(28);
      width: 100%;
      background-color: white;
      @extend %flex-middle-center;
      position: relative;

      .playback-rate {
        position: absolute;
        background: #ffffff;
        left: j(10);
        width: j(32);
        height: j(32);
        box-shadow: 0px j(5) j(22) rgba(0, 0, 0, 0.08);
        border-radius: 50%;
        font-weight: 400;
        font-size: j(12);
        color: var(--wl-text-color-secondary-2);
        cursor: pointer;
        z-index: 1;
        @extend %flex-middle-center;
      }

      .play {
        width: j(40);
        height: j(40);
        margin: 0 j(16);
        z-index: 1;
        border-radius: 50%;
        background-color: #fff;
        cursor: pointer;
        @extend %flex-middle-center;
        box-shadow: 0 j(5) j(22) rgba(0, 0, 0, 0.08);
      }

      .step {
        width: j(30);
        height: j(30);
        border-radius: 50%;
        background-color: white;
        z-index: 1;
        cursor: pointer;
        @extend %flex-middle-center;

        .forward,
        .back {
          width: j(23);
          height: j(23);
          background-size: 100%;
          font-weight: 400;
          font-size: j(12);
          color: var(--wl-text-color-secondary-2);
          background-repeat: no-repeat;
          @extend %flex-middle-center;
        }

        .forward {
          background-image: url("https://wlmvp-cos.weiling.cn/frontend/weilingMobileUI/audio-back.png?random=1");

          p {
            transform: translateX(2px);
          }
        }

        .back {
          background-image: url("https://wlmvp-cos.weiling.cn/frontend/weilingMobileUI/audio-up.png?random=1");

          p {
            transform: translateX(-2px);
          }
        }
      }
    }

    .speed-progress {
      width: 100%;
      height: 2px;
      background: var(--wl-btn-dashed-bg);
      border-radius: j(8);
      position: relative;
      margin-top: j(15);

      .played-process {
        position: absolute;
        height: 100%;
        top: 0;
        left: 0;
        width: 0;
        background-color: #1d9ffe;
      }

      .point {
        width: j(8);
        height: j(8);
        border-radius: 50%;
        top: 0;
        left: 40%;
        position: absolute;
        transform: translateY(calc(-25% - 1px));
        background-color: #1d9ffe;
      }
    }

    .time {
      margin-top: j(6);
      width: 100%;
      font-weight: 400;
      font-size: j(12);
      color: var(--wl-text-color-secondary-2);
      @extend %flex-middle;
      justify-content: space-between;
    }
  }
}
</style>
