<template>
	<view>
		<yb-video
      ref="video" :title="videoTitle" height="400rpx"
      autoplay
      render-type="renderjs"
      :crossOrigin="crossOrigin"
      :src="src"
			:initialTime="initialTime"
      :custom="custom"
      :poster="currentVideo.type == 2 ? poster : ''"
			:alwaysShowControls="currentVideo.type == 2"
      header
      controls
			open-direction="landscape-primary"
      exitDirection="portrait"
      object-fit="contain"
      @loadeddata="handleLoaded"
      @timeupdate="handleTimeUpdate"
			@ended="handleEnded"
			@loadstart="handleLoadStart"
      @canplay="handleCanPlay"
      @play="handlePlay"
			@fullscreenchange="handleFullscreenChange"
			@error="handleError"
    >
			<view v-if="!canPlay && !videoError" class="video-mask">{{ loadingText }}</view>
			<view v-if="canNext && !videoError" class="video-mask">
				<view>播放完成，倒计时 <text style="font-size: 40rpx; font-weight: bold;">{{ countdown }}</text>秒 后播放下一条</view>
				<view class="video-control-btn-group">
					<view class="video-control-btn" @click="handleReplay">重播</view>
					<view class="video-control-btn" @click="handleNext">立即播放</view>
				</view>
			</view>
			<view v-if="videoError && videoErrorMsg !== ''" class="video-mask">
				<view>{{ videoErrorMsg }}</view>
			</view>
		</yb-video>
	</view>
</template>

<script>
	import { BEFORE_NAVIGATE_BACK_EVENT } from "@/components/nav-bar/back-events"
	export default {
		props: {
      videoTitle: {
        type: String,
        default: '',
      },
      poster: {
        type: String,
        default: '',
      },
      currentVideoIndex: {
        type: Number,
        default: 0,
      },
      currentVideoList: {
        type: Array,
        default: () => [],
      },
      http: {
        type: Object,
        default: () => {},
      },
    },
		computed: {
			canNext() {
				return this.isEnded && this.currentVideoIndex < this.currentVideoList.length - 1
			},
			currentVideo() {
				return this.currentVideoList[this.currentVideoIndex] || {}
			}
		},
		watch: {
			currentVideo: {
				handler(newVal, oldVal) {
					if (newVal && newVal.id && newVal.id !== (oldVal && oldVal.id)) {
						if (oldVal && oldVal.id) {
							this._savePositionSnapshot(oldVal.id, parseInt(this.currentTime))
						}
						this._resetState();
						this.updateCustomConfig();
					}
				},
				immediate: true
			}
		},
		data () {
			return {
				src: '',
				isDestroyed: false,
				beforeBackHandler: null,
				canPlay: false,
				videoError: false,
				videoErrorMsg: '',
				loadingText: '媒体文件加载中...',
				currentTime: 0,
				initialTime: 0,
				isEnded: false,
				countdown: 10,
				countdownTimer: null,
				endedTimer: null,
				_requestVersion: 0,
				three: '',
				crossOrigin: '',
				danmu: [],
				quality: [],
				works: [],
				custom: {
          slots: [{
              innerHTML: '<div class="fast-progress-btn-box" style="left:15%;"><view class="yb-player-btn">-15s</view></div>',
              followControls: true,
              click: () => {
								console.log('快退 基准时间 ' + this.currentTime)
                this.$refs.video.seek(this.currentTime - 15)
              }
          },{
              innerHTML: '<div class="fast-progress-btn-box" style="right:15%;"><view class="yb-player-btn">+15s</view></div>',
              followControls: true,
              click: () => {
								console.log('快进 基准时间 ' + this.currentTime)
                this.$refs.video.seek(this.currentTime + 15)
              }
          }],
					header: {
						disableMore: true,
						disableBack: true,
					},
          controls: {
            disableDanmuSend: true,
            disableDanmuVisible: true,
						disableFullscreen: false,
          },
					progress: {
						rightSlots: [],
						disableFullscreen: false,
					},
				},
				text: ''
			}
		},
		beforeUnmount() {
			this._unbindBeforeBack()
			this._cleanup()
		},
		beforeDestroy() {
			this._unbindBeforeBack()
			this._cleanup()
		},
		created() {
			this._bindBeforeBack()
		},
		methods: {
			_resetState() {
				this.canPlay = false;
				this.isEnded = false;
				this.videoError = false;
				this.videoErrorMsg = '';
				this.loadingText = '媒体文件加载中...';
				this.currentTime = 0;
				this.initialTime = 0;
				this.isDestroyed = false;
				this._requestVersion++;
				if (this.countdownTimer) {
					clearInterval(this.countdownTimer);
					this.countdownTimer = null;
				}
				if (this.endedTimer) {
					clearTimeout(this.endedTimer);
					this.endedTimer = null;
				}
			},
			_bindBeforeBack() {
				if (this.beforeBackHandler || !uni.$on) return
				this.beforeBackHandler = () => {
					this._cleanup()
				}
				uni.$on(BEFORE_NAVIGATE_BACK_EVENT, this.beforeBackHandler)
			},
			_unbindBeforeBack() {
				if (!this.beforeBackHandler || !uni.$off) return
				uni.$off(BEFORE_NAVIGATE_BACK_EVENT, this.beforeBackHandler)
				this.beforeBackHandler = null
			},
			unload() {
				this._cleanup()
			},
			_cleanup() {
				if (this.isDestroyed) return
				this.isDestroyed = true
				const videoId = this.currentVideo ? this.currentVideo.id : null
				const position = parseInt(this.currentTime)
				if (this.$refs.video && this.$refs.video.unload) {
					this.$refs.video.unload()
				}
				if (this.countdownTimer) {
					clearInterval(this.countdownTimer);
					this.countdownTimer = null;
				}
				if (this.endedTimer) {
					clearTimeout(this.endedTimer);
					this.endedTimer = null;
				}
				this._savePositionSnapshot(videoId, position)
			},
			_savePositionSnapshot(videoId, position) {
				if (!videoId) return
				this._saveLocalVideoPosition(videoId, position)
				this._saveRemoteVideoPosition(videoId, position)
			},
			_saveLocalVideoPosition(videoId, position) {
				const videoPosition = JSON.parse(uni.getStorageSync('videoPosition') || '{"order":[], "position":{}}')
				if (!videoPosition.position) videoPosition.position = {}
				if (!videoPosition.order) videoPosition.order = []

				const videoKeys = new Set(videoPosition.order)
				if (videoKeys.size > 20) {
					const firstId = videoKeys.values().next().value
					delete videoPosition.position[firstId]
					videoKeys.delete(firstId)
					videoPosition.order = Array.from(videoKeys)
				}

				videoPosition.position[videoId] = position
				videoKeys.add(videoId)
				uni.setStorageSync('videoPosition', JSON.stringify(videoPosition))
			},
			_saveRemoteVideoPosition(videoId, position) {
				const http = this.http
				if (!http || !http.request) return
				http.request({
					url: "sociology/course/saveCoursePosition",
					method: "POST",
					data: { videoId, position },
					header: { 'Content-Type': 'application/json' },
				}).then(() => {
					console.log('保存视频播放位置成功：', videoId, position)
				}).catch(() => {
					console.log('保存视频播放位置失败')
				})
			},
			updateCustomConfig() {
				if (this.custom && this.custom.controls) {
					this.custom.controls.disableFullscreen = this.currentVideo.type == 2;
					this.custom.progress.disableFullscreen = this.currentVideo.type == 2;
				}
				this.changeSrc()
			},
      handleTimeUpdate (time) {
				if (this.isDestroyed) return
				if (!this.canPlay) return
				if (this.isEnded && time > 0) {
					this.isEnded = false
					if (this.countdownTimer) {
						clearInterval(this.countdownTimer)
						this.countdownTimer = null
					}
				}
        this.currentTime = time
				this._saveLocalVideoPosition(this.currentVideo.id, parseInt(time))
      },
			handleEnded () {
				if (this.isDestroyed) return
				this.endedTimer = setTimeout(() => {
					if (this.isDestroyed) return
					this.isEnded = true;
					this.startCountdown();
					this.currentTime = 0
				}, 300);

				this._savePositionSnapshot(this.currentVideo.id, parseInt(this.currentTime))

				if (!this.isDestroyed && this.$refs.video && this.$refs.video.exitFullscreen) {
					this.$refs.video.exitFullscreen()
				}
			},
			startCountdown() {
				this.countdown = 10;
				if (this.countdownTimer) {
					clearInterval(this.countdownTimer);
				}
				this.countdownTimer = setInterval(() => {
					this.countdown--;
					if (this.countdown <= 0) {
						clearInterval(this.countdownTimer);
						this.handleNext();
					}
				}, 1000);
			},
			handleLoadStart () {
				this.loadingText = '媒体文件加载完成，准备播放'
			},
			handleCanPlay () {
				if (this.isDestroyed) return
				this.canPlay = true
				this.videoError = false
			},
			handlePlay () {
				if (this.isDestroyed) return
				if (this.isEnded) {
					this.isEnded = false
				}
				if (this.countdownTimer) {
					clearInterval(this.countdownTimer)
					this.countdownTimer = null
				}
			},
			handleError () {
				this.videoError = true
				this.canPlay = false
			},
			handleNext () {
				if (this.canNext) {
					this.$emit('changeVideo', this.currentVideoIndex, 'next');
				}
			},
			handleReplay () {
				if (this.countdownTimer) {
					clearInterval(this.countdownTimer);
					this.countdownTimer = null;
				}
				this.$refs.video.seek(0)
				this.isEnded = false
				this.$refs.video.play()
			},
			changeSrc () {
				this.getPlayAuth()
			},
			handleFullscreenChange (data) {
				console.log('全屏状态改变：' + JSON.stringify(data))
				this.$emit('fullScreenChange', data.fullscreen)
			},
			handleLoaded (e) {
				console.log('视频加载状态：'+JSON.stringify(e))
				if (e.type == 'init') {
					this.loadingText = '媒体文件加载完成，立即播放'
				}
			},
			async getPlayAuth () {
				const version = ++this._requestVersion
				const videoId = this.currentVideo.id
				this.loadingText = '获取播放凭证...'

				const http = this.http
				if (!http || !http.request) return

				let res_check
				try {
					res_check = await http.request({
						url: `sociology/course/checkVideo`,
						method: "Post",
						data: { id: videoId },
						header: { "Content-Type": "application/json" },
					})
				} catch (e) {
					if (version !== this._requestVersion) return
					this.videoError = true
					this.videoErrorMsg = '获取播放凭证失败'
					return
				}

				if (version !== this._requestVersion) return

				this.loadingText = '验证媒体文件格式...'
				console.log("checkVideo接口返回视频信息" + JSON.stringify(res_check.video));
				if (this.$platform == 'ios') {
					if (res_check.video.type == 1 && (res_check.video.m3u8Url == null || res_check.video.m3u8Url == '')) {
						await this.recordErrorVideo(res_check.video, http)
						this.videoErrorMsg = '抱歉，苹果手机不支持此加密视频格式，您可以在安卓端观看本视频'
						return
					}
				}

				if (version !== this._requestVersion) return

				this.loadingText = '媒体文件加载中...'
				const options = {
					...res_check.video,
					videoId: res_check.video.video,
				}
				this.handlePlayAuth(options)
			},
			handlePlayAuth (options) {
				if (this.currentVideo.type == 1) {
					this.src = options.m3u8Url
				} else {
					this.src = options.videoUrl
				}

				const localPosition = JSON.parse(uni.getStorageSync('videoPosition') || '{"order":[], "position":{}}')
				this.initialTime = localPosition.position[this.currentVideo.id] !== undefined
					? localPosition.position[this.currentVideo.id]
					: (options.userCourseVideoPositionEntity ? options.userCourseVideoPositionEntity.position || 0 : 0)
			},
			recordErrorVideo (video, http) {
				if (!http || !http.request) return
				http.request({
					url: "medical/course/addErrorCourse",
					method: "POST",
					data: {
						"chapterId": video.chapterId,
						"videoId": video.id,
						"sort": video.sort 
					},
					header: { 'Content-Type': 'application/json' },
				}).then(() => {
					console.log('记录IOS不能看的视频成功 ' + JSON.stringify(video))
				}).catch(() => { console.log('数据报错') })
			},
		}
	}
</script>

<style lang="scss">
  ::v-deep .fast-progress-btn-box {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
		background-color: rgba(0, 0, 0, 0.3);
		border-radius: 14rpx;
		padding: 2px;
		display: flex;
		justify-content: center;
		align-items: center;

		.yb-player-btn {
			color: #fff;
			font-size: 28rpx;
			line-height: 1;
			padding: 10rpx 20rpx;
			border-radius: 10rpx;
			border: 1px solid #fff;
		}
    
  }
	::v-deep .video-mask {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 1);
    color: #fff;
    z-index: 2;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		gap: 20rpx;

		.video-control-btn-group {
			display: flex;
			justify-content: center;
			align-items: center;
			gap: 20rpx;
		}

		.video-control-btn {
			line-height: 1;
			padding: 5px 10px;
			border-radius: 5px;
			border: 1px solid #fff;
		}
  }
</style>
