import {
  defineComponent,
  nextTick,
  onMounted,
  onUnmounted,
  reactive,
  toRefs,
  watch
} from 'vue';
import { ref } from 'vue';
import styles from './index.module.less';

import TCPlayer from 'tcplayer.js';
import 'tcplayer.js/dist/tcplayer.min.css';
import iconLoop from '../../image/icon-loop.png';
import iconLoopActive from '../../image/icon-loop-active.png';
import iconplay from '../../image/icon-play.svg';
import iconpause from '../../image/icon-pause.svg';
import iconSpeed from '../../image/icon-speed.png';
import { NSlider } from 'naive-ui';
import { getSecondRPM } from '@/helpers/utils';
import { Slider, showToast } from 'vant';

export default defineComponent({
  name: 'video-play',
  props: {
    item: {
      type: Object,
      default: () => {
        return {};
      }
    },
    pageVisibility: {
      type: String,
      default: ''
    },
    show: {
      type: Boolean,
      default: false
    },
    showModel: {
      type: Boolean,
      default: false
    },
    isEmtry: {
      type: Boolean,
      default: false
    }
  },
  emits: [
    'canplay',
    'pause',
    'togglePlay',
    'ended',
    'reset',
    'close',
    'error',
    'loadedmetadata'
  ],
  setup(props, { emit, expose }) {
    const videoID = 'video' + Date.now() + Math.floor(Math.random() * 100);
    const speedBtnId = 'speed' + Date.now() + Math.floor(Math.random() * 100);
    const videoItem = ref();
    const { item, isEmtry } = toRefs(props);
    const data = reactive({
      speedInKbps: '',
      isOnline: true,
      timer: null as any,
      currentTime: 0,
      duration: 0,
      loop: false,
      playState: 'pause' as 'play' | 'pause',
      vudio: null as any,
      reload: false,
      speedControl: false,
      speedStyle: {
        left: '1px'
      },
      defaultSpeed: 1 // 默认速度
    });
    const videoRef = ref();
    const contetRef = ref();

    watch(
      () => props.show,
      val => {
        onToggleAudio(val ? 'play' : 'pause');
      }
    );
    watch(
      () => props.pageVisibility,
      val => {
        if (val === 'hidden' && props.show) {
          onToggleAudio('pause');
        }
      }
    );

    let playTimer = null as any;
    // 切换音频播放
    const onToggleAudio = (state: 'play' | 'pause') => {
      data.speedControl = false;
      clearTimeout(playTimer);
      if (state === 'play') {
        playTimer = setTimeout(() => {
          videoItem.value?.play();
          data.playState = 'play';
        }, 100);
      } else {
        videoItem.value?.pause();
        data.playState = 'pause';
      }
      emit('togglePlay', data.playState);
    };

    // 如果视屏异常后，需要重新播放视屏
    const onPlay = () => {
      data.speedControl = false;
      if (videoItem.value) {
        videoItem.value.src(item.value.content);
        emit('reset');
      }
    };

    /** 改变播放时间 */
    const handleChangeTime = (val: number) => {
      data.speedControl = false;
      data.currentTime = val;
      clearTimeout(data.timer);
      data.timer = setTimeout(() => {
        // elRef.value.currentTime = val;
        // data.timer = null;
        videoItem.value.currentTime(val);
        data.timer = null;
      }, 300);
    };

    let videoTimer = null as any;
    let videoTimerErrorCount = 0;
    const handlePlayVideo = () => {
      if (videoTimerErrorCount > 5) {
        return;
      }
      clearTimeout(videoTimer);
      nextTick(() => {
        videoItem.value?.play().catch((err: any) => {
          // console.log('🚀 ~ err:', err)
          videoTimer = setTimeout(() => {
            if (err?.message?.includes('play()')) {
              // emit('play');
            }
            handlePlayVideo();
          }, 1000);
        });
      });
      videoTimerErrorCount++;
    };

    const __init = () => {
      // videoEle
      if (videoItem.value) {
        console.log(videoItem.value, 'item.value', item.value);
        videoItem.value.poster(props.item.coverImg); // 封面
        videoItem.value.src(item.value.content); // url 播放地址
        videoItem.value.playbackRate(data.defaultSpeed);
        // 初步加载时
        videoItem.value.one('loadedmetadata', (e: any) => {
          videoItem.value.playbackRate(data.defaultSpeed);
          data.reload = false;
          // 获取时长
          data.duration = videoItem.value.duration();
          emit('canplay', videoItem.value);

          if (item.value.autoPlay && videoItem.value) {
            // videoItem.value?.play()
            nextTick(() => {
              videoTimerErrorCount = 0;
              videoItem.value.currentTime(0);
              nextTick(handlePlayVideo);
            });
          }
          emit('loadedmetadata', videoItem.value);
        });
        // 视频开始播放
        videoItem.value.on('play', () => {
          emit('close');
          emit('canplay');
        });
        //
        videoItem.value.on('pause', () => {
          data.playState = 'pause';
          emit('pause');
        });

        // 视频播放时加载
        videoItem.value.on('timeupdate', () => {
          if (data.timer) return;
          data.currentTime = videoItem.value.currentTime();
        });
        // 视频播放结束
        videoItem.value.on('ended', () => {
          data.playState = 'pause';
          // emit('ended');
        });

        videoItem.value.on('playing', () => {
          data.playState = 'play';
        });

        videoItem.value.on('canplay', (e: any) => {
          // console.log('canplay');
          data.duration = videoItem.value.duration();
          emit('canplay');
        });

        // 视频播放异常
        videoItem.value.on('error', (e: any) => {
          emit('error');
          console.log(e, 'error');
        });

        videoItem.value.on('progress', (e: any) => {
          console.log(e, 'progress');
        });
      }
    };

    watch(
      () => props.item,
      () => {
        videoItem.value.pause();
        videoItem.value.currentTime(0);
        if (item.value?.id) {
          __init();
          data.playState = 'pause';
        } else {
          videoItem.value.pause();
        }
        nextTick(() => {
          calculateSpeed(videoRef.value);
        });
      }
    );
    watch(
      () => props.showModel,
      () => {
        data.speedControl = false;
      }
    );

    const calculateSpeed = (element: any) => {
      let previousBytesLoaded = 0;
      let timer: any = null;
      let previousTime = Date.now();
      let buffterCatchArray = [] as any; // 缓存数据显示
      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`;
          data.speedInKbps = `0 KB/s`;
        }, 1500);
      }

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

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

        buffterCatch();
      }

      /**
       * 格式化视屏播放有效时间 - 合并区间
       * @param intervals [[], []]
       * @example [[4, 8],[0, 4],[10, 30]]
       * @returns [[0, 8], [10, 30]]
       */
      const formatEffectiveTime = (intervals: any[]) => {
        const res: any = [];
        intervals.sort((a, b) => a[0] - b[0]);
        let prev = intervals[0];
        for (let i = 1; i < intervals.length; i++) {
          const cur = intervals[i];
          if (prev[1] >= cur[0]) {
            // 有重合
            prev[1] = Math.max(cur[1], prev[1]);
          } else {
            // 不重合，prev推入res数组
            res.push(prev);
            prev = cur; // 更新 prev
          }
        }
        res.push(prev);
        return res;
      };

      // 获取视频总时长
      let noData = false;
      const onProgress = () => {
        const duration = element.duration;
        const currentTime = Date.now();
        const buffered = element.buffered;
        let currentBytesLoaded = 0;
        let currentLength = 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);
            buffterCatchArray = formatEffectiveTime([
              ...buffterCatchArray,
              [buffered.start(i), buffered.end(i)]
            ]);
          }
          // for (let i = 0; i < buffered.length; i++) {
          //   // 寻找当前时间之后最近的点
          //   if (buffered.start(buffered.length - 1 - i) < element.currentTime) {
          //     currentLength =
          //       (buffered.end(buffered.length - 1 - i) / duration) * 100;
          //     break;
          //   }
          // }
          currentBytesLoaded *= element.duration * element.seekable.end(0); // 更精确地近似字节加载量
        }

        // 计算未缓存的时间段
        const uncachedDuration = duration - cachedDuration;
        let uncachedTime = true; // 没有缓存时间
        buffterCatchArray.forEach((item: any) => {
          if (element.currentTime >= item[0] && uncachedTime <= item[1]) {
            uncachedTime = false;
          }
        });
        if (duration) {
          // const sliderDom: any = document.querySelector(
          //   '#' + audioSlider + ' .n-slider'
          // );
          // if (sliderDom) {
          //   sliderDom.style.setProperty(
          //     '--catch-width',
          //     uncachedDuration > 0 ? `${currentLength}%` : 'calc(100% + 17px)'
          //   );
          // }
          console.log(
            uncachedTime,
            duration,
            cachedDuration,
            'duration',
            buffterCatchArray,
            element.currentTime,
            currentLength + '%',
            isWaiting,
            currentBytesLoaded <= previousBytesLoaded
          );
        }

        const isNoBuffer = currentBytesLoaded <= previousBytesLoaded;
        // console.log(
        //   'progress',
        //   currentBytesLoaded,
        //   previousBytesLoaded,
        //   currentBytesLoaded > previousBytesLoaded
        // );
        // 计算未缓存的时间段
        // const uncachedDuration = duration - cachedDuration;
        // console.log(uncachedDuration, duration, cachedDuration, 'duration');
        // 如果存在未缓存的时间段，可以根据具体情况做出相应处理
        if (uncachedDuration > 0) {
          if (currentBytesLoaded > previousBytesLoaded && data.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) {
                data.speedInKbps = `${Number((kbps / 1024).toFixed(2))} M/s`;
              } else {
                data.speedInKbps = `${Number(speedInKbps)} KB/s`;
              }

              // 如果1秒钟没有返回就重置数据
              clearTimeout(timer);
              resetDownloadSpeed();
            }

            previousBytesLoaded = currentBytesLoaded;
            previousTime = currentTime;
            noData = false;
          }

          if (isNoBuffer && !uncachedTime) {
            // 如果1秒钟没有返回就重置数据

            if (!noData) {
              clearTimeout(timer);
              clearTimeout(bufferTimeout);
              setTimeout(() => {
                if (isBuffering) {
                  // 如果计时器到达且isBuffering仍为true，则认为缓存停止
                  console.log('停止缓存数据');
                  isBuffering = false;
                  data.speedInKbps = '';
                }
              }, 800);
            }

            noData = true;
          }

          if (element.paused || !data.isOnline) {
            clearTimeout(timer);
            data.speedInKbps = '';
          }

          if (!isWaiting) {
            resetBuffterCatch();
          }
        } else {
          clearTimeout(timer);
          buffterCatch(1000);
        }
      };

      const onWaiting = () => {
        console.log('waiting');
        isWaiting = true;
        let uncachedTime = true; // 没有缓存时间
        buffterCatchArray.forEach((item: any) => {
          if (element.currentTime >= item[0] && uncachedTime <= item[1]) {
            uncachedTime = false;
          }
        });

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

        // 如果有缓存检测计时器，则清除它
        if (bufferTimeout) {
          clearTimeout(bufferTimeout);
        }
      };

      const onCanplay = () => {
        console.log('canplay');
        isWaiting = false;
        resetBuffterCatch();
      };

      const onPause = () => {
        clearTimeout(timer);
        // 如果有缓存检测计时器，则清除它
        if (bufferTimeout) {
          clearTimeout(bufferTimeout);
        }
        data.speedInKbps = '';
      };

      element.removeEventListener('progress', onProgress);
      element.removeEventListener('waiting', onWaiting);
      element.removeEventListener('canplay', onCanplay);
      element.removeEventListener('pause', onPause);

      element.addEventListener('progress', onProgress);
      element.addEventListener('waiting', onWaiting);
      element.addEventListener('canplay', onCanplay);
      element.addEventListener('pause', onPause);
    };

    const onChangeOnlineStatus = (val: any) => {
      if (val.type === 'online') {
        data.isOnline = true;
      } else if (val.type === 'offline') {
        data.isOnline = false;
      }
    };

    onMounted(() => {
      videoItem.value = TCPlayer(videoID, {
        appID: '',
        controls: false
      }); // player-container-id 为播放器容器 ID，必须与 html 中一致
      __init();

      document.getElementById(speedBtnId)?.addEventListener('click', e => {
        e.stopPropagation();
        data.speedControl = !data.speedControl;
      });

      nextTick(() => {
        calculateSpeed(videoRef.value);
      });
      window.addEventListener('online', onChangeOnlineStatus);
      window.addEventListener('offline', onChangeOnlineStatus);
    });

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

    const pause = () => {
      videoItem.value.pause();
    };

    expose({
      onPlay,
      pause
    });
    return () => (
      <div class={styles.videoWrap}>
        <div class={styles.content}>
          <div ref={contetRef} class={styles.contentWrap}>
            <video
              style={{ width: '100%', height: '100%' }}
              id={videoID}
              ref={videoRef}
              preload="auto"
              playsinline
              webkit-playsinline
              x5-video-player-type="h5"></video>
          </div>
          <div class={styles.videoSection}></div>
        </div>

        <div
          class={[styles.controls, props.showModel ? '' : styles.hide]}
          onClick={(e: Event) => {
            e.stopPropagation();
            if (videoItem.value.paused()) return;
            emit('close');
          }}
          onTouchmove={(e: Event) => {
            if (videoItem.value.paused()) return;
            emit('close');
          }}>
          <div class={styles.time}>
            <div>{getSecondRPM(data.currentTime)}</div>
            <div>{getSecondRPM(data.duration)}</div>
          </div>
          <div class={styles.slider}>
            <NSlider
              tooltip={false}
              step={0.01}
              class={styles.timeProgress}
              value={data.currentTime}
              max={data.duration}
              onUpdate:value={val => handleChangeTime(val)}
            />
          </div>
          <div class={styles.actions}>
            <div
              class={styles.actionBtn}
              onClick={() =>
                onToggleAudio(data.playState === 'pause' ? 'play' : 'pause')
              }>
              <img src={data.playState === 'pause' ? iconplay : iconpause} />
            </div>
            <div
              class={styles.actionBtn}
              onClick={() => {
                data.loop = !data.loop;
                data.speedControl = false;
                videoItem.value.loop(data.loop);
                if (data.loop) {
                  setTimeout(() => {
                    showToast('已打开循环播放');
                  }, 60);
                } else {
                  setTimeout(() => {
                    showToast('已关闭循环播放');
                  }, 60);
                }
              }}>
              <img src={data.loop ? iconLoopActive : iconLoop} />
            </div>

            <div class={styles.actionBtn} id={speedBtnId}>
              <img src={iconSpeed} />
            </div>

            <div class={styles.downloadSpeed}>{data.speedInKbps}</div>
          </div>
        </div>

        <div
          style={{
            display: data.speedControl ? 'block' : 'none'
          }}>
          <div
            class={styles.sliderPopup}
            onClick={(e: Event) => {
              e.stopPropagation();
            }}>
            <i
              class={styles.iconAdd}
              onClick={() => {
                if (data.defaultSpeed >= 1.5) {
                  return;
                }

                if (videoItem.value) {
                  data.defaultSpeed = (data.defaultSpeed * 10 + 1) / 10;
                  videoItem.value.playbackRate(data.defaultSpeed);
                }
              }}></i>
            <Slider
              min={0.5}
              max={1.5}
              step={0.1}
              v-model={data.defaultSpeed}
              vertical
              barHeight={5}
              reverse
              onChange={() => {
                if (videoItem.value) {
                  videoItem.value.playbackRate(data.defaultSpeed);
                }
              }}>
              {{
                button: () => (
                  <div class={styles.sliderPoint}>
                    {data.defaultSpeed}
                    <span>x</span>
                  </div>
                )
              }}
            </Slider>
            <i
              class={[styles.iconCut]}
              onClick={() => {
                if (data.defaultSpeed <= 0.5) {
                  return;
                }
                if (videoItem.value) {
                  data.defaultSpeed = (data.defaultSpeed * 10 - 1) / 10;
                  videoItem.value.playbackRate(data.defaultSpeed);
                }
              }}></i>
          </div>
        </div>
      </div>
    );
  }
});
