<script setup lang="ts">
import type { CourseChapterType, CourseResourceType, VideoRecordType, PlayItemType } from '../types'
import type { VideoJsPlayer, VideoJsPlayerOptions } from 'video.js'
import { throttle } from 'lodash'
import { useStorage, useElementVisibility } from '@vueuse/core'
import { Swiper, SwiperSlide } from 'swiper/vue'
import 'swiper/css'
import AppVideoPlayer from '@/components/base/AppVideoPlayer.vue'
import { getCoursePlayInfo, getVideoRecords, uploadVideoRecords } from '../api'

interface Props {
  chapterList: CourseChapterType[]
}

const props = defineProps<Props>()
const emit = defineEmits<{
  (e: 'updateResource', resource: CourseResourceType | undefined): void
  (e: 'timeupdate', time: number): void
}>()

const options = $ref<VideoJsPlayerOptions>()

const route = useRoute()
let courseId = $ref<string>('')
let chapterId = $ref<string>('')
let sectionId = $ref<string>('')
let resourceId = $ref<string>('')
let semesterId = $ref<string>('')
watchEffect(() => {
  courseId = route.query.course_id as string
  chapterId = route.query.chapter_id as string
  sectionId = route.query.section_id as string
  resourceId = route.query.resource_id as string
  semesterId = route.query.semester_id as string
})

const playerWrapperRef = ref(null)
const playerIsVisible = useElementVisibility(playerWrapperRef)

/**
 * 视频播放器相关
 */
let src = $ref<{ src: string; type: string }>()
function changeSrc(data: PlayItemType) {
  // src = { src: data.PlayURL, type: 'application/x-mpegURL' }
  src = { src: data.PlayURL, type: 'video/mp4' }
}
// 跳过片头
const isSkip = $ref(useStorage('isSkip', false))
const skipTime = $ref<number>(6)
// 连续播放
const isAutoPlayNext = $ref(useStorage('isAutoPlayNext', false))

// 播放器ready
let isReady = $ref<boolean>(false)
let videoJsPlayer = $ref<VideoJsPlayer | null>(inject('videoJsPlayer'))
const onReady = (player: VideoJsPlayer) => {
  isReady = true
  videoJsPlayer = player
}

// 当前章
const chapter = $computed(() => {
  return props.chapterList.find(item => item.id === chapterId)
})
// 当前节
const section = $computed(() => {
  return chapter?.sections.find(item => item.id === sectionId)
})

// 当前节下的视频列表
const sectionVideoList = $computed<CourseResourceType[]>(() => {
  const list = section?.resources ?? []
  return list.filter(item => item.resource_type === 2)
})

watchEffect(() => {
  if (sectionVideoList.length) {
    const found = sectionVideoList.find(item => item.resource_id === resourceId)
    resourceId = found ? resourceId : sectionVideoList[0]?.resource_id
  }
})

// 当前资源
const resource = $computed(() => {
  return section?.resources.find(item => item.resource_id === resourceId && item.resource_type === 2)
})
watchEffect(() => {
  emit('updateResource', resource)
})
// 切换视频资源
function changeResource(data: CourseResourceType) {
  throttledFn && throttledFn.flush()
  resourceId = data.resource_id
  videoJsPlayer?.pause()
}

// 进度信息
const progress = reactive<VideoRecordType>({
  cumulative_playing_time: '',
  current_playing_time: 0,
  max_playing_time: 0,
  valid_playing_time: 0,
  watchedTimePoint: []
})

let playList = $ref<PlayItemType[]>([])
const currentPlayList = $computed<PlayItemType[]>(() => {
  return playList
    .filter(item => item.StreamType === 'video' && item.Format === 'mp4')
    .map(item => {
      const DefinitionMap: Record<string, string> = { FD: '流畅', LD: '标清', SD: '高清', HD: '超清' }
      const DefinitionName = DefinitionMap[item.Definition] || item.Definition
      return { ...item, DefinitionName }
    })
})

// 获取视频信息
async function fetchInfo() {
  if (!resource?.info.source_id) throw '资源不存在'
  const res = await getCoursePlayInfo({ source_id: resource.info.source_id })
  playList = res.data.playing_list
}
// 获取视频记录
async function fetchVideoRecords() {
  if (!resource) throw '资源不存在'
  const res = await getVideoRecords({
    chapter_id: chapterId,
    course_id: courseId,
    section_id: sectionId,
    semester_id: semesterId,
    video_id: resourceId
  })
  const { detail = {} } = res.data
  progress.current_playing_time = detail.current_playing_time ? parseFloat(detail.current_playing_time) : 0
  progress.max_playing_time = detail.max_playing_time ? parseFloat(detail.max_playing_time) : 0
  progress.valid_playing_time = detail.valid_playing_time ? parseFloat(detail.valid_playing_time) : 0
  progress.watchedTimePoint = []
  console.log('info', progress.current_playing_time)
}
watchEffect(async () => {
  if (!resource) return
  await fetchVideoRecords()
  await fetchInfo()
  console.log('watch', progress.current_playing_time)
  changeSrc(currentPlayList[0])
})

function setVideoInfo() {
  if (!videoJsPlayer) return
  // 上次播放结束，设置进度为0
  if (videoJsPlayer.duration() - progress.current_playing_time < 1) {
    progress.current_playing_time = 0
  }
  // 统计，增加默认时间10秒
  progress.valid_playing_time = progress.valid_playing_time || 10
  // 跳过片头
  if (isSkip) {
    // 跳过片头
    if (progress.current_playing_time < skipTime) {
      progress.current_playing_time = skipTime
    }
    // 有效时间增加跳过片头的时间
    if (!progress.valid_playing_time) {
      progress.valid_playing_time = skipTime + 10
    }
  }
  // 初始化跳转到上次观看的时间点
  videoJsPlayer.currentTime(progress.current_playing_time)
  console.log('seek', progress.current_playing_time)
  videoJsPlayer.play()
}
const throttledFn = throttle(
  () => {
    uploadVideoRecords({
      chapter_id: chapterId,
      course_id: courseId,
      section_id: sectionId,
      semester_id: semesterId,
      video_id: resourceId,
      valid_playing_time: progress.valid_playing_time,
      current_playing_time: progress.current_playing_time,
      max_playing_time: progress.max_playing_time,
      cumulative_playing_time: progress.watchedTimePoint.join(',') || progress.current_playing_time.toString()
    })
    // 清空已经上传过的观看时间点
    progress.watchedTimePoint = []
  },
  5000
  // { leading: false }
)
// 视频加载完成
function onLoadedData() {
  console.log('onLoadedData')
  setVideoInfo()
}

// 进度更新
function onTimeUpdate() {
  const time = Math.floor(videoJsPlayer?.currentTime() ?? 0)
  if (!time || videoJsPlayer?.paused()) return
  emit('timeupdate', time)
  console.log('onTimeUpdate', time)
  // 更新观看累计时长
  if (time !== progress.current_playing_time) {
    progress.valid_playing_time++
  }
  // 更新当前播放时间
  progress.current_playing_time = time
  // 观看的最大点
  progress.max_playing_time = Math.max(time, progress.max_playing_time)
  // 观看时间点
  const hasTimePoint = progress.watchedTimePoint.includes(time)
  !hasTimePoint && progress.watchedTimePoint.push(time)

  throttledFn()
}
// 播放结束
function onEnded() {
  console.log('onEnd')
  throttledFn && throttledFn.flush()
  // 自动播放下一个视频
  if (isAutoPlayNext) {
    const currentIndex = sectionVideoList.findIndex(item => item.resource_id === resourceId)
    const next = sectionVideoList[currentIndex + 1]
    next && changeResource(next)
  }
}
function onSeeked() {
  console.log('onSeeked')
  throttledFn && throttledFn.flush()
}
onUnmounted(() => {
  throttledFn && throttledFn.cancel()
})
</script>

<template>
  <div ref="playerWrapperRef" :style="resource ? `height: 510px` : ''">
    <div class="player-box" :class="{ 'is-pinned': !playerIsVisible }">
      <AppVideoPlayer
        :options="options"
        :src="src"
        @ready="onReady"
        @loadeddata="onLoadedData"
        @timeupdate="onTimeUpdate"
        @seeked="onSeeked"
        @ended="onEnded"
        style="width: 100%; height: 100%"
        v-if="src"
      ></AppVideoPlayer>
    </div>
  </div>
  <!-- 设置 -->
  <teleport to=".vjs-control-bar" v-if="isReady">
    <el-popover trigger="hover" effect="dark" placement="top" :teleported="false" :show-arrow="false" width="40px">
      <template #reference>
        <button class="vjs-hd-control vjs-control vjs-button" type="button">
          <span class="vjs-icon-hd"></span>
        </button>
      </template>
      <ul class="video-definition">
        <li
          v-for="(item, index) in currentPlayList"
          :key="index"
          :class="{ 'is-active': item.PlayURL === src.src }"
          @click="changeSrc(item)"
        >
          {{ item.DefinitionName }}
        </li>
      </ul>
    </el-popover>
    <el-popover trigger="hover" effect="dark" placement="top" :teleported="false" :show-arrow="false" width="140px">
      <template #reference>
        <button class="vjs-cog-control vjs-control vjs-button" type="button">
          <span class="vjs-icon-cog"></span>
        </button>
      </template>
      <ul class="video-actions">
        <li>始终跳过片头 <el-switch size="small" v-model="isSkip"></el-switch></li>
        <li>连续播放 <el-switch size="small" v-model="isAutoPlayNext"></el-switch></li>
      </ul>
    </el-popover>
  </teleport>
  <swiper :slidesPerView="'auto'" :spaceBetween="30">
    <swiper-slide
      v-for="item in sectionVideoList"
      :key="item.id"
      class="video-item"
      :class="{ 'is-active': item.resource_id === resourceId }"
      @click="changeResource(item)"
    >
      <img :src="item.info?.cover" />
      <p>{{ item.info.name }}</p>
    </swiper-slide>
  </swiper>
</template>

<style lang="scss" scoped>
.player-box {
  width: 100%;
  height: 100%;
  &.is-pinned {
    position: fixed;
    bottom: 40px;
    right: 40px;
    width: 400px;
    height: 220px;
    z-index: 9999;

    .vjs-hd-control,
    .vjs-cog-control,
    :deep(.vjs-fullscreen-control) {
      display: none;
    }
  }
}
.vjs-icon-hd,
.vjs-icon-cog {
  font-size: 1.8em;
}
:deep(.vjs-fullscreen-control) {
  order: 1;
}
.video-item {
  position: relative;
  margin: 20px 0;
  width: 200px;
  height: 100px;
  border-radius: 5px;
  cursor: pointer;
  overflow: hidden;
  box-sizing: border-box;
  p {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 0 10px;
    font-size: 14px;
    line-height: 30px;
    color: #fff;
    background-color: rgba(0, 0, 0, 0.5);
    text-align: center;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
  }
  img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  &.is-active {
    border: 2px solid var(--main-color);
  }
}
.video-definition {
  font-size: 12px;
  li {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.2em 0;
    font-size: 1.2em;
    line-height: 1.4em;
    &:hover {
      background: rgba(115, 133, 159, 0.5);
    }
    &.is-active {
      color: #2b333f;
      background-color: #fff;
    }
  }
}
.video-actions {
  font-size: 12px;
  li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.2em 5px;
    font-size: 1.2em;
    line-height: 1.4em;
  }
}
:deep(.el-popover) {
  min-width: auto;
  background-color: rgba(43, 51, 63, 0.7);
  border: 0;
  border-radius: 0;
  padding: 0;
  margin-bottom: -12px !important;
}
</style>
