<template>
  <div>
    <audio :src="src" v-bind="$attrs" v-on="$listeners" :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">
          <WlPic v-show="!isPlaying" :src="audio_play_icon" />
          <WlPic v-show="isPlaying" :src="audio_stop_icon" />
        </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>
import { audio_play_icon, audio_stop_icon } from "@packages/utils/cdn";
import AudioBackground from "./components/AudioBackground/index.vue";
import WlPic from "@packages/components/Common/WlPic/src/index.vue";
export default {
  name: "WlAudio",
  components: { WlPic, AudioBackground },
  props: {
    src: {
      type: String,
      default: "",
    },
    needPlaybackRate: {
      type: Boolean,
      default: false,
    },
    playbackRateArr: {
      type: Array,
      default: () => [0.25, 0.5, 1, 1.25, 1.5, 2],
    },
    loop: {
      type: Boolean,
      default: false,
    },
    stepSecond: {
      type: Number,
      default: 5,
    },
    defaultTime: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      duration: 0,
      currentTime: 0,
      isPlaying: false,
      rate: 1,
      lineNumber: 10,
      audio_play_icon,
      audio_stop_icon
    };
  },
  computed: {
    played_rate() {
      if (this.currentTime > this.duration) {
        return "100%";
      }
      if (this.duration === 0) return "0%";
      return (this.currentTime / this.duration) * 100 + "%";
    },
    formatSecond() {
      return function (seconds) {
        seconds = parseInt(seconds);
        if (Number.isNaN(seconds) || !Number.isSafeInteger(seconds)) {
          return "00:00";
        } else {
          const mintue = parseInt(seconds / 60);
          const hour = parseInt(seconds / 3600);
          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: {
    defaultTime: {
      handler(val) {
        if (val < 0) {
          this.currentTime = 0;
        } else {
          this.currentTime = val;
        }
        if (this.isPlaying) {
          this.$refs.audioRef.currentTime = this.currentTime;
        }
      },
      immediate: true,
    },
  },
  mounted() {
    this.$nextTick(() => {
      const width = this.$refs.audioControlsRef.clientWidth;
      this.lineNumber = Math.ceil(width / 20);
      this.$refs.audioRef.addEventListener("onerror", (err) => {
        this.$emit("onError", err);
      });
    });
  },
  methods: {
    loadedmetadata() {
      this.duration = this.$refs.audioRef.duration;
      if (this.currentTime > this.duration) {
        this.currentTime = this.duration;
      }
      this.$emit("onLoadedmetadata", this.$refs.audioRef);
    },
    ended() {
      this.isPlaying = false;
      this.$emit("onEnded");
    },
    pause() {
      this.$emit("onPause");
    },
    play() {
      this.$emit("onPlay");
    },
    playing() {
      this.$emit("onPlaying");
    },
    waiting() {
      this.$emit("onWaiting");
    },
    timeupdate() {
      this.currentTime = this.$refs.audioRef.currentTime;
    },
    onClick() {
      if (!this.isPlaying) {
        if (this.currentTime >= this.duration) {
          this.currentTime = 0;
        }
        this.$refs.audioRef.currentTime = this.currentTime;
        this.$refs.audioRef.play();
      } else {
        this.$refs.audioRef.pause();
      }
      this.isPlaying = !this.isPlaying;
    },
    onForward() {
      if (this.currentTime + this.stepSecond > this.duration) {
        this.$refs.audioRef.currentTime = this.duration;
      } else {
        this.$refs.audioRef.currentTime = this.currentTime + this.stepSecond;
      }
      this.$emit("onForward");
    },
    onBack() {
      if (this.currentTime - this.stepSecond <= 0) {
        this.$refs.audioRef.currentTime = 0;
      } else {
        this.$refs.audioRef.currentTime = this.currentTime - this.stepSecond;
      }
      this.$emit("onBack");
    },
    onChangeRate() {
      let index = this.playbackRateArr.findIndex(
        (ele) => parseFloat(ele) === parseFloat(this.rate)
      );
      index = (index + 1) % this.playbackRateArr.length;
      this.rate = this.playbackRateArr[index];
      this.$refs.audioRef.playbackRate = parseFloat(this.rate);
      this.$emit("onChangeRate", this.rate);
    },
    onChangeTime(time) {
      time = parseInt(time);
      if (time > this.duration) {
        this.$refs.audioRef.currentTime = this.duration;
      } else {
        this.$refs.audioRef.currentTime = time;
      }
    },
  },
};
</script>

<style lang="scss" scoped>
@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: #919699;
      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%;
      cursor: pointer;
      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: #919699;
        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(2);
        }
      }

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

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

  .speed-progress {
    width: 100%;
    height: 2px;
    background: #f7f7f7;
    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: #919699;
    @extend %flex-middle;
    justify-content: space-between;
  }
}
</style>
