import {
  defineComponent,
  reactive,
  ref,
  nextTick,
  onMounted,
  watch,
  onUnmounted
} from 'vue';
import styles from './audio.module.less';
import iconplay from '../image/icon-pause.png';
import iconpause from '../image/icon-play.png';
import iconReplay from '../image/icon-replay.png';
import { NSlider } from 'naive-ui';
import Vudio from 'vudio.js';
import tickMp3 from '../image/tick.mp3';

export default defineComponent({
  name: 'audio-play',
  props: {
    item: {
      type: Object,
      default: () => {
        return {};
      }
    },
    activeStatus: {
      type: Boolean,
      default: false
    },
    isEmtry: {
      type: Boolean,
      default: false
    },
    imagePos: {
      type: String,
      default: 'left'
    }
  },
  emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset'],
  setup(props, { emit, expose }) {
    const audioForms = reactive({
      paused: true,
      speedInKbps: '',
      currentTimeNum: 0,
      isOnline: false,
      currentTime: '00:00',
      durationNum: 0,
      duration: '00:00',
      showBar: true,
      afterMa3: true,
      count: 0,
      previousBytesLoaded: 0,
      previousTime: Date.now()
    });
    const canvas: any = ref();
    const audio: any = ref();
    let vudio: any = null;

    // 切换音频播放
    const onToggleAudio = (e?: any) => {
      e?.stopPropagation();
      // console.log(audio.value.paused, 'audio.value.paused');
      if (audio.value.paused) {
        audio.value.play();
        audioForms.afterMa3 = false;
      } else {
        audio.value?.pause();
      }
      audioForms.paused = audio.value?.paused;
      e?.target?.focus();
      emit('togglePlay', audioForms.paused);
    };

    const onInit = (audio: undefined, canvas: undefined) => {
      if (!vudio) {
        vudio = new Vudio(audio, canvas, {
          effect: 'waveform',
          accuracy: 256,
          width: 1024,
          height: 600,
          waveform: {
            maxHeight: 200,
            color: [
              [0, '#44D1FF'],
              [0.5, '#44D1FF'],
              [0.5, '#198CFE'],
              [1, '#198CFE']
            ],
            prettify: false
          }
        });
        vudio.dance();
      }
    };

    // 对时间进行格式化
    const timeFormat = (num: number) => {
      if (num > 0) {
        const m = Math.floor(num / 60);
        const s = num % 60;
        return (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
      } else {
        return '00:00';
      }
    };

    //
    const toggleHideControl = (isShow: false) => {
      audioForms.showBar = isShow;
    };

    const onReplay = () => {
      if (!audio.value) return;
      audio.value.currentTime = 0;
    };

    let vudio1 = null;
    const canvas1: any = ref();
    const audio1: any = ref();
    nextTick(() => {
      vudio1 = new Vudio(audio1.value, canvas1.value, {
        effect: 'waveform',
        accuracy: 256,
        width: 1024,
        height: 600,
        waveform: {
          maxHeight: 200,
          color: [
            [0, '#44D1FF'],
            [0.5, '#44D1FF'],
            [0.5, '#198CFE'],
            [1, '#198CFE']
          ],
          prettify: false
        }
      });
      vudio1.dance();
    });

    watch(
      () => props.activeStatus,
      (val: any) => {
        // console.log(val, 'val');
        audioForms.count = 0;
        if (val && props.item.autoPlay) {
          vudio = null;
          onToggleAudio();
        } else {
          audio.value.pause();
        }
      }
    );

    const calculateSpeed = (element: any) => {
      let previousBytesLoaded = 0;
      let timer: any = null;
      let previousTime = Date.now();
      let isWaiting = false;

      // 缓存检测状态
      let isBuffering = false;
      // 缓存检测计时器
      let bufferTimeout: any = null;
      // 设定一个检测缓存停止的时间间隔，这里我们设置为2500毫秒（2秒）
      const BUFFER_CHECK_INTERVAL = 2500;

      function resetDownloadSpeed() {
        timer = setTimeout(() => {
          // displayElement.textContent = `视屏下载速度: 0 KB/s`;
          audioForms.speedInKbps = `0 KB/s`;
        }, 1500);
      }

      function buffterCatch() {
        // 设定一个计时器，检查是否在指定的时间内再次触发了progress事件
        bufferTimeout = setTimeout(() => {
          if (isBuffering) {
            // 如果计时器到达且isBuffering仍为true，则认为缓存停止
            console.log('停止缓存数据。');
            isBuffering = false;
            audioForms.speedInKbps = '';
          }
        }, BUFFER_CHECK_INTERVAL);
      }

      function resetBuffterCatch() {
        // 如果有缓存检测计时器，则清除它
        if (bufferTimeout) {
          clearTimeout(bufferTimeout);
        }
        // 标记为正在缓存
        isBuffering = true;

        buffterCatch();
      }

      element.addEventListener('loadedmetadata', () => {
        // 获取视频总时长
        const duration = element.duration;

        element.addEventListener('progress', () => {
          const currentTime = Date.now();
          const buffered = element.buffered;
          let currentBytesLoaded = 0;

          // 计算视频已缓存的总时长
          let cachedDuration = 0;
          if (buffered.length > 0) {
            for (let i = 0; i < buffered.length; i++) {
              currentBytesLoaded += buffered.end(i) - buffered.start(i);
              cachedDuration += buffered.end(i) - buffered.start(i);
            }
            currentBytesLoaded *= element.duration * element.seekable.end(0); // 更精确地近似字节加载量
          }

          // console.log(
          //   'progress',
          //   currentBytesLoaded,
          //   previousBytesLoaded,
          //   currentBytesLoaded > previousBytesLoaded
          // );
          // 计算未缓存的时间段
          const uncachedDuration = duration - cachedDuration;
          console.log(uncachedDuration, duration, cachedDuration, 'duration');
          // 如果存在未缓存的时间段，可以根据具体情况做出相应处理
          if (uncachedDuration > 0) {
            if (
              currentBytesLoaded > previousBytesLoaded &&
              audioForms.isOnline
            ) {
              const timeDiff = (currentTime - previousTime) / 1000; // 时间差转换为秒
              const bytesDiff = currentBytesLoaded - previousBytesLoaded; // 字节差值
              const speed = bytesDiff / timeDiff; // 字节每秒

              if (!element.paused) {
                const kbps = speed / 1024;
                const speedInKbps = kbps.toFixed(2); // 转换为千字节每秒并保留两位小数
                if (kbps > 1024) {
                  audioForms.speedInKbps = `${Number(
                    (kbps / 1024).toFixed(2)
                  )} M/s`;
                } else {
                  audioForms.speedInKbps = `${Number(speedInKbps)} KB/s`;
                }
              }

              previousBytesLoaded = currentBytesLoaded;
              previousTime = currentTime;
            }

            if (!element.paused && audioForms.isOnline) {
              // 如果1秒钟没有返回就重置数据
              clearTimeout(timer);
              resetDownloadSpeed();
            } else {
              audioForms.speedInKbps = '';
            }

            resetBuffterCatch();
          } else {
            resetBuffterCatch();
          }
        });
        element.addEventListener('waiting', () => {
          console.log('waiting');
          isWaiting = true;

          if (!element.paused) {
            // 如果1秒钟没有返回就重置数据
            clearTimeout(timer);
            resetDownloadSpeed();
          }

          // 如果有缓存检测计时器，则清除它
          if (bufferTimeout) {
            clearTimeout(bufferTimeout);
          }
        });
        element.addEventListener('canplay', () => {
          console.log('canplay');
          isWaiting = false;
          resetBuffterCatch();
        });

        element.addEventListener('pause', () => {
          clearTimeout(timer);
          // 如果有缓存检测计时器，则清除它
          if (bufferTimeout) {
            clearTimeout(bufferTimeout);
          }
          audioForms.speedInKbps = '';
        });
        // element.addEventListener('error', () => {
        //   element.pause();
        // });
      });
    };

    const onChangeOnlineStatus = (val: any) => {
      if (val.type === 'online') {
        audioForms.isOnline = true;
      } else if (val.type === 'offline') {
        audioForms.isOnline = false;
      }
    };
    onMounted(() => {
      nextTick(() => {
        calculateSpeed(audio.value);
      });
      window.addEventListener('online', onChangeOnlineStatus);
      window.addEventListener('offline', onChangeOnlineStatus);
    });

    onUnmounted(() => {
      window.removeEventListener('online', onChangeOnlineStatus);
      window.removeEventListener('offline', onChangeOnlineStatus);
    });

    expose({
      toggleHideControl
    });

    return () => (
      <div class={styles.audioWrap}>
        <div class={styles.audioContainer}>
          <audio
            ref={audio}
            crossorigin="anonymous"
            src={props.item.content}
            onEnded={() => {
              audioForms.paused = true;
              emit('ended');
            }}
            onTimeupdate={() => {
              audioForms.currentTime = timeFormat(
                Math.round(audio.value?.currentTime || 0)
              );
              audioForms.currentTimeNum = audio.value?.currentTime || 0;

              if (audioForms.count <= 1) {
                audioForms.count += 1;
                onInit(audio.value, canvas.value);
              }
            }}
            onLoadedmetadata={() => {
              audioForms.duration = timeFormat(
                Math.round(audio.value?.duration)
              );
              audioForms.durationNum = audio.value?.duration;

              if (props.item.autoPlay && audio.value && props.activeStatus) {
                // audio.value.play();
                onToggleAudio();
              }
              if (audio.value) {
                audio.value.stop = () => {
                  audio.value?.pause();
                  audioForms.paused = true;
                  emit('togglePlay', audioForms.paused);
                };
                audio.value.onPlay = () => {
                  audio.value?.play();
                  audioForms.paused = false;
                  onInit(audio.value, canvas.value);
                  emit('togglePlay', audioForms.paused);
                };
              }
              emit('loadedmetadata', audio.value);
            }}
            onProgress={(e: any) => {
              console.log(e, 'loadedmetadata onProgress');
            }}></audio>

          <canvas ref={canvas}></canvas>

          {audioForms.afterMa3 && (
            <div class={styles.tempVudio}>
              <audio ref={audio1} src={tickMp3} />
              <canvas ref={canvas1}></canvas>
            </div>
          )}
        </div>

        <div
          class={[
            styles.controls,
            audioForms.showBar ? '' : styles.sectionAnimate
          ]}
          onClick={(e: MouseEvent) => {
            e.stopPropagation();
            emit('reset');
          }}>
          <div class={styles.slider}>
            <NSlider
              value={audioForms.currentTimeNum}
              step={0.01}
              max={audioForms.durationNum}
              tooltip={false}
              onUpdate:value={(val: number) => {
                audio.value.currentTime = val;
                audioForms.currentTimeNum = val;
                audioForms.currentTime = timeFormat(Math.round(val || 0));
              }}
            />
          </div>
          <div class={styles.tools}>
            {props.imagePos === 'right' ? (
              <>
                <div class={styles.actions}>
                  <div class={styles.time}>
                    <div
                      class="plyr__time plyr__time--current"
                      aria-label="Current time">
                      {audioForms.currentTime}
                    </div>
                    <span class={styles.line}>/</span>
                    <div
                      class="plyr__time plyr__time--duration"
                      aria-label="Duration">
                      {audioForms.duration}
                    </div>
                  </div>
                </div>
                <div class={styles.actions}>
                  <div class={styles.actionWrap}>
                    <div class={styles.downloadSpeed}>
                      {audioForms.speedInKbps}
                    </div>
                    <button class={styles.iconReplay} onClick={onReplay}>
                      <img src={iconReplay} />
                    </button>
                    <div class={styles.actionBtn} onClick={onToggleAudio}>
                      {audioForms.paused ? (
                        <img class={styles.playIcon} src={iconplay} />
                      ) : (
                        <img class={styles.playIcon} src={iconpause} />
                      )}
                    </div>
                  </div>
                </div>
              </>
            ) : (
              <>
                <div class={styles.actions}>
                  <div class={styles.actionWrap}>
                    <div class={styles.actionBtn} onClick={onToggleAudio}>
                      {audioForms.paused ? (
                        <img class={styles.playIcon} src={iconplay} />
                      ) : (
                        <img class={styles.playIcon} src={iconpause} />
                      )}
                    </div>
                    <button class={styles.iconReplay} onClick={onReplay}>
                      <img src={iconReplay} />
                    </button>
                    <div class={styles.downloadSpeed}>
                      {audioForms.speedInKbps}
                    </div>
                  </div>
                </div>
                <div class={styles.actions}>
                  <div class={styles.time}>
                    <div
                      class="plyr__time plyr__time--current"
                      aria-label="Current time">
                      {audioForms.currentTime}
                    </div>
                    <span class={styles.line}>/</span>
                    <div
                      class="plyr__time plyr__time--duration"
                      aria-label="Duration">
                      {audioForms.duration}
                    </div>
                  </div>
                </div>
              </>
            )}
          </div>
        </div>
      </div>
    );
  }
});
