<template>
	<view class="cell" :style="frameStyle">
		<video
			v-if="src"
			:id="playerId"
			class="cell-video"
			:style="frameStyle"
			:src="src"
			:controls="false"
			:show-play-btn="false"
			:enable-progress-gesture="false"
			:object-fit="fitMode"
			:http-cache="true"
			:muted="muted"
			:autoplay="playing"
			:playsinline="true"
			webkit-playsinline
			:loop="true"
			@play="onVideoPlay"
			@pause="onVideoPause"
			@loadedmetadata="onLoadedMetadata"
			@canplay="onCanPlay"
			@ended="onVideoEnded"
			@error="onVideoError"
		/>
		<image
			v-if="coverEnabled && showCover"
			class="cell-cover"
			:style="frameStyle"
			:src="cover"
			mode="aspectFill"
		/>
	</view>
</template>

<script>
/**
 * 短视频单元格（.vue 版）
 *
 * 注意：Vue2 不会把 data 里以 _/$ 开头的字段代理到 this 上，
 * 定时器字段禁止用 _replayKickTimers 这种命名，否则 this.xxx 恒为 undefined。
 */
export default {
	name: 'FeedMediaCell',
	props: {
		playerId: { type: String, default: 'feed-vid-0' },
		src: { type: String, default: '' },
		remoteSrc: { type: String, default: '' },
		cover: { type: String, default: '' },
		coverEnabled: { type: Boolean, default: true },
		playing: { type: Boolean, default: false },
		frameW: { type: Number, default: 375 },
		frameH: { type: Number, default: 667 },
		fitMode: { type: String, default: 'cover' }
	},
	data() {
		return {
			showCover: true,
			booted: false,
			muted: true,
			playKickTimer: null,
			replayKickTimers: [],
			audioWakeTimers: []
		}
	},
	computed: {
		frameStyle() {
			return {
				width: `${this.frameW}px`,
				height: `${this.frameH}px`
			}
		}
	},
	watch: {
		playing(next, prev) {
			this.syncPlayback(next)
			if (next && !prev) this.scheduleAudioWake()
			if (!next) this.clearAudioWakeTimers()
		},
		src(next, prev) {
			if (next !== prev) {
				this.showCover = true
				this.booted = false
				this.muted = true
				this.clearPlayKickTimer()
				this.clearReplayKickTimers()
				this.clearAudioWakeTimers()
			}
		}
	},
	mounted() {
		if (this.playing) this.ensurePlayback()
	},
	beforeDestroy() {
		this.clearPlayKickTimer()
		this.clearReplayKickTimers()
		this.clearAudioWakeTimers()
	},
	methods: {
		clearReplayKickTimers() {
			const list = Array.isArray(this.replayKickTimers) ? this.replayKickTimers : []
			list.forEach((id) => clearTimeout(id))
			this.replayKickTimers = []
		},
		clearPlayKickTimer() {
			if (!this.playKickTimer) return
			clearTimeout(this.playKickTimer)
			this.playKickTimer = null
		},
		clearAudioWakeTimers() {
			const list = Array.isArray(this.audioWakeTimers) ? this.audioWakeTimers : []
			list.forEach((id) => clearTimeout(id))
			this.audioWakeTimers = []
		},
		videoCtx() {
			return uni.createVideoContext(this.playerId, this)
		},
		requestPlay() {
			if (!this.src || !this.playing) return
			const ctx = this.videoCtx()
			if (!ctx) return
			try {
				ctx.play()
			} catch (_) {}
		},
		ensurePlayback() {
			if (!this.playing || !this.src) return
			this.muted = true
			this.clearPlayKickTimer()
			this.requestPlay()
			this.playKickTimer = setTimeout(() => {
				this.playKickTimer = null
				if (this.playing) this.requestPlay()
			}, 120)
		},
		scheduleAudioWake() {
			this.clearAudioWakeTimers()
			const timers = []
			;[0, 90, 220, 480].forEach((delay) => {
				timers.push(
					setTimeout(() => {
						if (!this.playing) return
						this.requestPlay()
					}, delay)
				)
			})
			this.audioWakeTimers = timers
		},
		syncPlayback(shouldPlay) {
			if (!this.src) return
			if (shouldPlay) {
				this.ensurePlayback()
			} else {
				this.muted = true
				this.clearPlayKickTimer()
				this.clearReplayKickTimers()
				const ctx = this.videoCtx()
				if (!ctx) return
				try {
					ctx.pause()
				} catch (_) {}
			}
		},
		onVideoPlay() {
			this.showCover = false
			this.booted = true
			if (this.playing) this.muted = false
		},
		onVideoPause() {},
		onLoadedMetadata() {
			if (this.playing) this.ensurePlayback()
		},
		onCanPlay() {
			if (this.playing) this.ensurePlayback()
		},
		onVideoEnded() {
			if (!this.playing) return
			this.replayFromStart()
		},
		replayFromStart() {
			this.showCover = false
			this.clearPlayKickTimer()
			this.clearReplayKickTimers()
			const ctx = this.videoCtx()
			if (!ctx) return
			const kick = () => {
				if (!this.playing || !this.src) return
				try {
					ctx.seek(0)
				} catch (_) {}
				try {
					ctx.play()
				} catch (_) {}
			}
			kick()
			const timers = []
			;[40, 120, 280, 520].forEach((ms) => {
				timers.push(setTimeout(() => kick(), ms))
			})
			this.replayKickTimers = timers
		},
		onVideoError() {
			this.showCover = true
			this.muted = true
			if (this.remoteSrc && this.src !== this.remoteSrc) {
				this.$emit('fallback', this.remoteSrc)
			}
		}
	}
}
</script>

<style scoped>
.cell {
	position: relative;
	background-color: #000000;
	overflow: hidden;
}
.cell-video {
	background-color: #000000;
}
.cell-cover {
	position: absolute;
	left: 0;
	top: 0;
}
</style>