<template>
  <div class="player-wrap">
    <div ref="playerRef" class="artplayer-container"></div>
  </div>
</template>

<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import Artplayer from 'artplayer'
import Hls from 'hls.js'
import type { EpisodeData } from '@/api/qishier'
import { getEpisodeProgress, saveEpisodeProgress } from '@/utils/playHistory'

type ArtWithHls = Artplayer & {
  hls?: Hls
}

const props = defineProps<{
  episode: EpisodeData | null
  autoNext: boolean
}>()

const emit = defineEmits<{
  error: [message: string]
  endedNext: []
}>()

const playerRef = ref<HTMLDivElement | null>(null)
let art: ArtWithHls | null = null

function destroyPlayer() {
  if (art?.hls) {
    art.hls.destroy()
    art.hls = undefined
  }

  if (art) {
    art.destroy()
    art = null
  }

  if (playerRef.value) {
    playerRef.value.innerHTML = ''
  }
}

function buildPlayer(episode: EpisodeData) {
  if (!playerRef.value) return

  art = new Artplayer({
    container: playerRef.value,
    url: episode.videoUrl,
    autoplay: true,
    autoSize: true,
    fullscreen: true,
    fullscreenWeb: true,
    pip: true,
    setting: true,
    playbackRate: true,
    hotkey: true,

    autoHide: 2000,

    mutex: true,
    theme: '#f5c542',
    moreVideoAttr: {
      playsInline: true
    } as any,
    customType: {
      m3u8(video: HTMLVideoElement, url: string, artInstance: Artplayer) {
        const artplayer = artInstance as ArtWithHls

        if (Hls.isSupported()) {
          const hls = new Hls()
          artplayer.hls = hls
          hls.loadSource(url)
          hls.attachMedia(video)
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
          video.src = url
        } else {
          emit('error', '当前浏览器不支持 m3u8 播放')
        }
      }
    }
  }) as ArtWithHls

  art.type = 'm3u8'

  const restore = () => {
    const progress = getEpisodeProgress(episode.id)
    if (progress > 0 && art?.video) {
      try {
        art.video.currentTime = progress
      } catch {
        // ignore
      }
    }
  }

  art.on('video:loadedmetadata', restore)

  art.on('video:timeupdate', () => {
    if (art?.video) {
      saveEpisodeProgress(episode.id, art.video.currentTime)
    }
  })

  art.on('video:ended', () => {
    if (props.autoNext) {
      emit('endedNext')
    }
  })

  art.on('error', () => {
    emit('error', '视频播放失败')
  })
}

async function initPlayer() {
  destroyPlayer()

  if (!props.episode) return

  await nextTick()
  buildPlayer(props.episode)
}

watch(
    () => props.episode?.id,
    async () => {
      await initPlayer()
    }
)

watch(
    () => props.autoNext,
    () => {
      // 让 ended 事件读取最新 autoNext 值
    }
)

onMounted(async () => {
  await initPlayer()
})

onBeforeUnmount(() => {
  destroyPlayer()
})
</script>

<style scoped>
.player-wrap {
  width: 100%;
  background: #000;
}

.artplayer-container {
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000;
}

:deep(.artplayer-app) {
  width: 100%;
  height: 100%;
}
</style>
