<!--
* @FileDescription: 播放器
* @Author: 黄琪勇
* @Date:2024-04-03 18:30:09
-->
<template>
   <div
      @keydown="handleVideoKeydown"
      @mousemove="handleVideoMousemove"
      @click="handleVideoClick"
      class="videoPlay"
      :class="{ isHideController: !isShowController }"
      tabindex="-1"
   >
      <video class="videoPlayBox" :id="videoId" preload="auto" playsinline webkit-playsinline></video>
      <div class="videoController" @click.stop @touchstart.stop>
         <div class="timeController">{{ `${formatTime(timeController.currentTime)} / ${formatTime(timeController.duration)}` }}</div>
         <n-slider
            class="sliderController"
            :keyboard="false"
            :value="timeController.currentTimeSilder"
            :tooltip="isShowController"
            :step="0.01"
            @update:value="handleSilderChange"
            :on-dragend="handleTimeChange"
            :max="timeController.duration"
            :format-tooltip="(value:number) => {
                  return formatTime(value)
            }"
         />
         <div class="playController">
            <div class="leftPlayController">
               <img @click="handlePlay" :src="require(`./img/${playController.type === 'play' ? 'iconPause' : 'iconPlay'}.png`)" />
               <img @click="handleLoop" :src="require(`./img/${playController.loop ? 'iconLoopActive' : 'iconLoop'}.png`)" />
               <img ref="btnSpendDom" src="./img//iconSpeed.png" />
               <el-popover
                  @show="handlePopoverTimeHide"
                  ref="popoverSpendDom"
                  :virtual-ref="btnSpendDom"
                  trigger="click"
                  placement="top"
                  :teleported="false"
                  popper-class="palySpeedPopover"
                  virtual-triggering
               >
                  <div class="sliderSpeedCon">
                     <img @click="handlePalySpeed(playController.speedStep)" src="./img/jia.png" />
                     <n-slider
                        class="sliderSpeed"
                        :tooltip="false"
                        :keyboard="false"
                        :value="playController.palySpeed"
                        @update:value="handlePalySpeedChange"
                        vertical
                        :step="playController.speedStep"
                        :max="playController.maxSpeed"
                        :min="playController.minSpeed"
                     >
                        <template #thumb>
                           <div class="thumb">{{ playController.palySpeed.toFixed(1) + "X" }}</div>
                        </template>
                     </n-slider>
                     <img @click="handlePalySpeed(-playController.speedStep)" src="./img/jian.png" />
                  </div>
               </el-popover>
            </div>
            <div class="rightPlayController">
               <div class="videoName">
                  <div>{{ videoName || "" }}</div>
               </div>
            </div>
         </div>
      </div>
   </div>
</template>

<script setup lang="ts">
import TCPlayer from "tcplayer.js"
import "tcplayer.js/dist/tcplayer.min.css"
import { onMounted, onUnmounted, ref, reactive, watch, toRef, watchEffect } from "vue"
import { UUID } from "@/libs/tools"
import { formatTime } from "./tools"
import { NSlider } from "naive-ui"

const props = defineProps<{
   disableEvents?: boolean
   isShowController?: boolean
}>()
const emits = defineEmits<{
   (e: "ready"): void //播放器初始化完成
   (e: "ended"): void //播放结束
   (e: "playbackRate"): void //播放速度改动时候
}>()
const videoId = "video" + UUID()
let playerVm: Record<string, any>
let isReady = false // 是否初始化播放器播放器
const videoName = ref("")

/* 时间控制器 */
const timeController = reactive({
   currentTime: 0, // 当前时间
   duration: 0, // 总时长
   currentTimeSilder: 0,
   isDrag: false
})
/* 播放控制器 */
const btnSpendDom = ref()
const popoverSpendDom = ref()
let _popoverSpendTime: any
// 定时隐藏
function handlePopoverTimeHide() {
   _popoverSpendTime && clearTimeout(_popoverSpendTime)
   _popoverSpendTime = setTimeout(() => {
      popoverSpendDom.value?.hide()
   }, 5000)
}
const playController = reactive<{
   type: "play" | "pause"
   loop: boolean
   minSpeed: number
   maxSpeed: number
   speedStep: number
   palySpeed: number
}>({
   type: "pause", //play|pause
   loop: false,
   minSpeed: 0.5,
   maxSpeed: 1.5,
   speedStep: 0.1,
   palySpeed: 1
})
watch(
   () => playController.palySpeed,
   () => {
      // 值变化 重新计算隐藏时间
      handlePopoverTimeHide()
   }
)
/* 是否显示控制器 */
const isShowController = ref(true)
watchEffect(() => {
   isShowController.value = props.isShowController
})
let _showTimer: any
onMounted(() => {
   initVideo()
})
onUnmounted(() => {
   playerVm?.dispose()
})
/**
 * 初始化播放器
 */
function initVideo() {
   playerVm = TCPlayer(videoId, {
      controls: false,
      //autoplay: true,  // 自动播放前1秒暂停不了，改为loadedmetadata调用播放 实现自动播放
      loop: false
   })
   // 初始化完成
   playerVm.ready(() => {
      console.log("播放器初始化完成")
      isReady = true
      emits("ready")
   })
   // 开始加载数据时
   playerVm.on("loadstart", () => {
      // 重新设置播放倍速  因为切换视频播放倍速会重置
      playerVm.playbackRate(playController.palySpeed)
   })
   playerVm.on("loadedmetadata", () => {
      console.log("loadedmetadata")
      playerVm.play()
   })
   //总时长变化时候
   playerVm.on("durationchange", () => {
      timeController.duration = playerVm.duration()
   })
   //当前播放时间变化
   playerVm.on("timeupdate", () => {
      timeController.currentTime = playerVm.currentTime()
      if (!timeController.isDrag) {
         timeController.currentTimeSilder = timeController.currentTime
      }
   })
   playerVm.on("play", () => {
      playController.type = "play"
   })
   playerVm.on("pause", () => {
      playController.type = "pause"
   })
   // 播放结束
   playerVm.on("ended", () => {
      emits("ended")
   })
}
/**
 * 播放  需要在ready之后调用
 */
// 接口请求可能在播放之前 所以这里等待播放器初始化
let _time: any
function playVideo({ src, name }: { src: string; name: string }) {
   videoName.value = name
   _time && clearInterval(_time)
   if (isReady) {
      handlePlayVideo(src)
   } else {
      _time = setInterval(() => {
         if (isReady) {
            clearInterval(_time)
            handlePlayVideo(src)
         }
      }, 60)
   }
}
function handlePlayVideo(src: string) {
   playerVm?.src(src)
   showController()
}

/* 时间控制器 */
function handleTimeChange(value?: number) {
   playerVm.currentTime(value || timeController.currentTimeSilder)
   timeController.isDrag = false
}
function handleSilderChange(value: number) {
   timeController.isDrag = true
   timeController.currentTimeSilder = value
}
// 快进或者快退
function speedCurrentTime(type: "fast" | "slow") {
   handleTimeChange(timeController.currentTime + (type === "fast" ? 5 : -5))
   showController()
}
/* 播放控制器 */
function handlePlay() {
   playController.type === "pause" ? playerVm.play() : playerVm.pause()
   showController()
}
// 暂停
function pauseVideo() {
   playerVm.pause()
   showController()
}
// 循环播放
function handleLoop() {
   playController.loop ? playerVm.loop(false) : playerVm.loop(true)
   playController.loop = playerVm.loop()
}
// 播放速度
function handlePalySpeedChange(value: number) {
   playController.palySpeed = value
   playerVm.playbackRate(value)
   emits("playbackRate")
}
function handlePalySpeed(value: number) {
   const palySpeed = parseFloat((playController.palySpeed + value).toFixed(1))
   if (palySpeed > playController.maxSpeed || palySpeed < playController.minSpeed) {
      return
   }
   handlePalySpeedChange(palySpeed)
}
function handleVideoClick() {
   if (props.disableEvents) return
   handlePlay()
}
function handleVideoKeydown(e: KeyboardEvent) {
   if (props.disableEvents) return
   const key = e.key
   if (key === " ") {
      handlePlay()
   } else if (key === "ArrowLeft") {
      speedCurrentTime("slow")
   } else if (key === "ArrowRight") {
      speedCurrentTime("fast")
   }
}
function handleVideoMousemove() {
   if (props.disableEvents) return
   showController()
}
/* 是否显示控制器 */
function showController() {
   if (props.disableEvents) return
   isShowController.value = true
   _showTimer && clearTimeout(_showTimer)
   _showTimer = setTimeout(tryHideController, 3000)
}
function tryHideController() {
   if (playController.type === "play") {
      isShowController.value = false
   }
}
defineExpose({
   playVideo,
   pauseVideo,
   handlePlay,
   speedCurrentTime,
   playType: toRef(playController, "type")
})
</script>

<style lang="scss" scoped>
.videoPlay {
   width: 100%;
   height: 100%;
   position: relative;
   overflow: hidden;
   :deep(.videoPlayBox) {
      &.tcp-skin .tcp-right-click-popup-menu {
         display: none;
      }
   }
   .videoPlayBox {
      width: 100%;
      height: 100%;
   }
   &.isHideController {
      cursor: none;
      .videoController {
         opacity: 0;
         transform: translateY(100%);
      }
   }
   .videoController {
      position: absolute;
      width: 100%;
      left: 0;
      bottom: 0;
      padding: 0 30px 15px;
      background: linear-gradient(0deg, rgba(0, 0, 0, 0.5), transparent);
      color: #fff;
      transition: all 0.5s;
      // &:hover {   //取消鼠标移入不隐藏
      //    cursor: initial;
      //    opacity: initial !important;
      //    transform: initial !important;
      // }
      .timeController {
         font-weight: 500;
         font-size: 20px;
         color: #ffffff;
         line-height: 30px;
      }
      & > :deep(.sliderController.n-slider) {
         --n-rail-color: #c9c9cb !important;
         --n-fill-color: #ff8057 !important;
         --n-fill-color-hover: #ff8057 !important;
      }
      .playController {
         display: flex;
         justify-content: space-between;
         .leftPlayController {
            margin-left: -10px;
            display: flex;
            & > img {
               cursor: pointer;
               width: 48px;
               height: 48px;
               margin-right: 26px;
            }
            & > :deep(.palySpeedPopover.el-popover.el-popper) {
               min-width: initial;
               width: 59px !important;
               height: 264px;
               background: url("./img/bg.png") no-repeat;
               background-size: 100% 100%;
               box-shadow: none;
               border: none;
               padding: 12px 0 20px;
               .el-popper__arrow {
                  display: none;
               }
               .sliderSpeedCon {
                  width: 100%;
                  height: 100%;
                  display: flex;
                  justify-content: center;
                  align-items: center;
                  flex-direction: column;
                  & > img {
                     cursor: pointer;
                     flex-shrink: 0;
                     width: 30px;
                     height: 31px;
                  }
                  .sliderSpeed.n-slider {
                     flex-grow: 1;
                     padding: 6px 0;
                     --n-rail-width-vertical: 5px !important;
                     --n-rail-color: #c9c9cb !important;
                     --n-fill-color: #ff8057 !important;
                     --n-fill-color-hover: #ff8057 !important;
                     .thumb {
                        height: 22px;
                        padding: 0 6px;
                        background: #ffffff;
                        box-shadow: 0px 2px 4px 0px rgba(102, 102, 102, 0.77);
                        border-radius: 11px;
                        text-align: center;
                        line-height: 22px;
                        font-weight: 500;
                        font-size: 15px;
                        color: #ff8057;
                     }
                  }
               }
            }
         }
         .rightPlayController {
            display: flex;
            align-items: center;
            .videoName {
               font-weight: 500;
               font-size: 20px;
               color: #ffffff;
            }
         }
      }
   }
}
</style>
