<!--
* @FileDescription: 播放器
* @Author: 黄琪勇
* @Date:2024-04-03 18:30:09
-->
<template>
   <div
      @keydown="props.listenWinEvents || handleVideoKeydown"
      @mousemove="handleVideoMousemove"
      class="videoPlay"
      :class="{ isHideController: !isShowController }"
      tabindex="-1"
   >
      <video class="videoPlayBox" @click="handlePlay" :id="videoId" preload="auto" playsinline webkit-playsinline></video>
      <div class="videoController" @click.stop>
         <div class="timeController">{{ `${formatTime(timeController.currentTime)} / ${formatTime(timeController.duration)}` }}</div>
         <el-slider
            class="sliderController"
            @change="handleTimeChange"
            @mousedown="handleSilderMousedown"
            v-model="timeController.currentTimeSilder"
            :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" />
                     <el-slider
                        tooltip-class="sliderSpeedTitTooltip"
                        class="sliderSpeed"
                        @change="handlePalySpeedChange"
                        v-model="playController.palySpeed"
                        vertical
                        :step="playController.speedStep"
                        :max="playController.maxSpeed"
                        :min="playController.minSpeed"
                        :format-tooltip="(num:number) => {
                           return num.toFixed(1)
                        }"
                     />
                     <img @click="handlePalySpeed(-playController.speedStep)" src="./img/jian.png" />
                  </div>
               </el-popover>
            </div>
            <div class="rightPlayController"></div>
         </div>
      </div>
      <slot></slot>
   </div>
</template>

<script setup lang="ts">
import TCPlayer from "tcplayer.js"
import "tcplayer.js/dist/tcplayer.min.css"
import { onMounted, onUnmounted, ref, reactive, watch } from "vue"
import { UUID } from "@/libs/tools"
import { formatTime } from "./tools"
import { addClass, removeClass, setStyle } from "@/libs/tools"

const props = defineProps<{
   listenWinEvents?: boolean
}>()
const emits = defineEmits<{
   (e: "ready"): void //播放器初始化完成
   (e: "ended"): void //播放结束
}>()

const videoId = "video" + UUID()
let playerVm: Record<string, any>

/* 时间控制器 */
const timeController = reactive({
   currentTime: 0, // 当前时间
   duration: 0, // 总时长
   currentTimeSilder: 0,
   isDrag: false
})
/* 播放控制器 */
const btnSpendDom = ref()
const popoverSpendDom = ref()
let _popoverSpendTime: any
let _sliderSpeedTitTime: any
const body = document.querySelector("body")
const name = "_sliderSpeedTit"
function handleSliderSpeedTitShow() {
   const sliderSpeedTitTooltipDom = document.querySelector(".sliderSpeedTitTooltip.el-popper")
   sliderSpeedTitTooltipDom?.setAttribute("data-popper-placement", "top")
   setStyle(
      document.querySelector(".sliderSpeedTitTooltip.el-popper .el-popper__arrow") as any,
      {
         transform: `translate(15px, 0)`
      } as any
   )
   setStyle(
      sliderSpeedTitTooltipDom as any,
      {
         "z-index": "3000",
         inset: "auto auto 0px 0px",
         transform: `translate(172px, ${-156 - (playController.palySpeed - 0.5) * 10 * 15}px)`
      } as any
   )
   addClass(body, name)
   clearTimeout(_sliderSpeedTitTime)
   _sliderSpeedTitTime = setTimeout(() => {
      removeClass(body, name)
   }, 800)
}
// 定时隐藏
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)
let _showTimer: any
onMounted(() => {
   initVideo()
   if (props.listenWinEvents) {
      document.addEventListener("keydown", handleVideoKeydown)
   }
})
onUnmounted(() => {
   if (props.listenWinEvents) {
      document.removeEventListener("keydown", handleVideoKeydown)
   }
   playerVm?.dispose()
})
/**
 * 初始化播放器
 */
function initVideo() {
   playerVm = TCPlayer(videoId, {
      controls: false,
      autoplay: true,
      loop: false
   })
   // 初始化完成
   playerVm.ready(() => {
      console.log("播放器初始化完成")
      emits("ready")
   })
   // 开始加载数据时
   playerVm.on("loadstart", () => {
      // 重新设置播放倍速  因为切换视频播放倍速会重置
      playerVm.playbackRate(playController.palySpeed)
   })
   //总时长变化时候
   playerVm.on("durationchange", () => {
      //duration和currentTime 时间向上取整Math.ceil
      timeController.duration = Math.ceil(playerVm.duration())
   })
   //当前播放时间变化
   playerVm.on("timeupdate", () => {
      //duration和currentTime 时间向上取整Math.ceil
      timeController.currentTime = Math.ceil(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之后调用
 */
function playVideo({ src }: { src: string }) {
   playerVm?.src(src)
   showController()
}

/* 时间控制器 */
function handleTimeChange(value: number | number[]) {
   playerVm.currentTime(value || 0)
   timeController.isDrag = false
}
function handleSilderMousedown() {
   timeController.isDrag = true
}
// 快进或者快退
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 | number[]) {
   playerVm.playbackRate(value)
}
function handlePalySpeed(value: number) {
   const palySpeed = parseFloat((playController.palySpeed + value).toFixed(1))
   if (palySpeed > playController.maxSpeed || palySpeed < playController.minSpeed) {
      return
   }
   playController.palySpeed = palySpeed
   handlePalySpeedChange(palySpeed)
   handleSliderSpeedTitShow()
}
/* 是否显示控制器 */
function handleVideoKeydown(e: KeyboardEvent) {
   const key = e.key
   if (key === " ") {
      handlePlay()
   } else if (key === "ArrowLeft") {
      speedCurrentTime("slow")
   } else if (key === "ArrowRight") {
      speedCurrentTime("fast")
   }
}
function handleVideoMousemove() {
   showController()
}
function showController() {
   isShowController.value = true
   _showTimer && clearTimeout(_showTimer)
   _showTimer = setTimeout(tryHideController, 3000)
}
function tryHideController() {
   if (playController.type === "play") {
      isShowController.value = false
   }
}
defineExpose({
   playVideo,
   pauseVideo
})
</script>

<style lang="scss">
body._sliderSpeedTit {
   .sliderSpeedTitTooltip {
      display: initial !important;
   }
}
</style>
<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;
      .timeController {
         font-weight: 500;
         font-size: 20px;
         color: #ffffff;
         line-height: 30px;
      }
      & > :deep(.sliderController.el-slider) {
         --el-slider-button-wrapper-offset: -12px;
         --el-slider-button-wrapper-size: 28px;
         --el-slider-button-size: 20px;
         --el-slider-height: 4px;
         --el-slider-border-radius: 2px;
         --el-slider-main-bg-color: #ff8057;
         --el-slider-runway-bg-color: rgba(255, 255, 255, 0.5);
         height: 28px;
         .el-slider__button {
            border: none;
            &:hover {
               transform: scale(1.1);
            }
         }
      }
      .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.el-slider {
                     flex-grow: 1;
                     padding: 10px 0;
                     --el-slider-button-wrapper-offset: -9px;
                     --el-slider-button-wrapper-size: 24px;
                     --el-slider-button-size: 16px;
                     --el-slider-height: 6px;
                     --el-slider-border-radius: 4px;
                     --el-slider-main-bg-color: #ff8057;
                     --el-slider-runway-bg-color: rgba(255, 255, 255, 0.5);
                     .el-slider__button {
                        border: none;
                        &:hover {
                           transform: scale(1.1);
                        }
                     }
                  }
               }
            }
         }
      }
   }
}
</style>
