<template>
	<view class="carousel" :style="{width: boxWidth, height: boxHeight}">
		<!-- Swiper 轮播 -->
		<swiper :current="current" :autoplay="autoplay ? interval : 0" :interval="interval" :circular="true"
			:indicator-dots="false" :display-multiple-items="1" @change="onSwiperChange" class="swiper-container">
			<swiper-item v-for="(item, index) in normalizedList" :key="index" class="slide">
				<!-- 图片 -->
				<image v-if="item.mediaType==='image'" :src="item.src"
					:class="['img', imageModeMap[index]==='contain'?'vertical':'']" @load="onImageLoad($event,index)"
					@tap="onImageTap(index)" />

				<!-- 视频 -->
				<view v-else-if="item.mediaType==='video'" class="video-wrapper" @click.stop="playVideo(index)">
					<video :id="'video-'+index" :src="item.src" :poster="item.poster" :controls="playingIndex===index"
						:show-center-play-btn="false" object-fit="cover" @play="onVideoPlay" @pause="onVideoPause"
						class="video" />
					<view v-if="playingIndex!==index" class="play-btn">▶</view>
				</view>

				<!-- VR -->
				<view v-else-if="item.mediaType==='vr'" class="vr-wrapper">
					<image class="vr-cover" :src="item.src" mode="aspectFit" />
					<image class="vr-icon" :src="vrIcon" mode="aspectFit" @tap.stop="enterVR()" />
				</view>
			</swiper-item>
		</swiper>

		<!-- 自定义点指示器 -->
		<view v-if="indicator==='dot'" class="dots">
			<view v-for="(item,index) in normalizedList" :key="index" class="dot" :class="{active:index===current}" />
		</view>

		<!-- 自定义箭头 -->
		<view v-if="indicator==='arrow'" class="arrow left" @click.stop="prev">‹</view>
		<view v-if="indicator==='arrow'" class="arrow right" @click.stop="next">›</view>

		<!-- 底部分区指示器 -->
		<view v-if="autoTypeIndicateList.length" class="type-bar">
			<view v-for="(item,index) in autoTypeIndicateList" :key="index" class="type-segment"
				:class="{active:current>=item.startIndex && current<=item.endIndex}"
				:style="{width:getSegmentWidth+'%'}" @click.stop="jumpToType(item)">
				{{item.name}}
			</view>
		</view>

		<!-- 右下角索引 -->
		<view class="index-display">{{current+1}} / {{normalizedList.length}}</view>

		<!-- 双击放大 -->
		<view v-if="zoomed" class="zoom-overlay" @tap="zoomed=false">
			<image :src="zoomSrc" mode="widthFix" class="zoom-img" />
		</view>
	</view>
</template>

<script>
	export default {
		name: 'Carousel',
		props: {
			list: {
				type: Array,
				required: true
			},
			indicator: {
				type: String,
				default: 'dot'
			}, // dot | arrow | none
			autoplay: {
				type: Boolean,
				default: false
			},
			interval: {
				type: Number,
				default: 3000
			},
			vrIcon: {
				type: String,
				default: ''
			},
			boxWidth: {
				type: String,
				default: '100%'
			},
			boxHeight: {
				type: String,
				default: '500rpx'
			},
			vrViewPage: {
				type: String,
				default: ''
			},
			assetsId: {
				type: String,
				default: ''
			}
		},
		data() {
			return {
				current: 0,
				playingIndex: null,
				imageModeMap: {},
				zoomed: false,
				zoomSrc: '',
				lastTap: 0
			}
		},
		computed: {
			normalizedList() {
				const vr = [],
					other = []
				this.list.forEach(item => item.mediaType === 'vr' ? vr.push(item) : other.push(item))
				return [...vr, ...other]
			},
			autoTypeIndicateList() {
				const list = this.normalizedList
				if (!list.length) return []
				const result = []
				let startIndex = 0,
					bizType = list[0].bizType
				for (let i = 1; i <= list.length; i++) {
					if (i === list.length || list[i].bizType !== bizType) {
						result.push({
							type: bizType,
							name: bizType,
							startIndex,
							endIndex: i - 1
						})
						startIndex = i
						bizType = list[i] && list[i].bizType
					}
				}
				return result
			},
			getSegmentWidth() {
				return this.autoTypeIndicateList.length ? 100 / this.autoTypeIndicateList.length : 100
			}
		},
		methods: {
			onSwiperChange(e) {
				this.current = e.detail.current
				this.stopVideo()
			},
			// 图片模式判断
			onImageLoad(e, index) {
				const {
					width,
					height
				} = e.detail
				if (!width || !height) return
				this.$set(this.imageModeMap, index, width >= height ? 'cover' : 'contain')
			},
			// 双击放大
			onImageTap(index) {
				const now = new Date().getTime()
				if (now - this.lastTap < 300) {
					this.zoomed = true
					this.zoomSrc = this.normalizedList[index].src
				}
				this.lastTap = now
			},
			// 视频
			playVideo(index) {
				if (this.playingIndex === index) return
				this.stopVideo()
				this.playingIndex = index
				uni.createVideoContext('video-' + index, this).play()
			},
			stopVideo() {
				if (this.playingIndex !== null) {
					uni.createVideoContext('video-' + this.playingIndex, this).pause()
					this.playingIndex = null
				}
			},
			onVideoPlay() {},
			onVideoPause() {},
			// VR
			enterVR() {
				this.stopVideo()
				this.$u.route({
					url: this.vrViewPage,
					params: {
						title: 'vr看资产',
						id: this.assetsId
					}
				})
			},
			// 分区跳转
			jumpToType(item) {
				this.current = item.startIndex
			},
			prev() {
				const len = this.normalizedList.length
				this.current = (this.current - 1 + len) % len
			},
			next() {
				const len = this.normalizedList.length
				this.current = (this.current + 1) % len
			}
		}
	}
</script>

<style scoped>
	.carousel {
		position: relative;
		width: 100%;
		height: 100%;
	}

	.swiper-container,
	swiper-item {
		width: 100%;
		height: 100%;
	}

	.slide {
		display: flex;
		justify-content: center;
		align-items: center;
		width: 100%;
		height: 100%;
	}

	.img {
		width: 100%;
		height: 100%;
		object-fit: cover;
	}

	.img.vertical {
		object-fit: contain;
	}

	.video-wrapper {
		width: 100%;
		height: 100%;
		position: relative;
	}

	.video {
		width: 100%;
		height: 100%;
	}

	.play-btn {
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		width: 80rpx;
		height: 80rpx;
		line-height: 80rpx;
		text-align: center;
		background: rgba(0, 0, 0, 0.5);
		color: #fff;
		border-radius: 50%;
		font-size: 40rpx;
	}

	.vr-wrapper {
		position: relative;
	}

	.vr-icon {
		position: absolute;
		top: 50%;
		left: 12%;
		transform: translate(-50%, -50%);
		width: 100rpx;
		height: 100rpx;
		background: rgba(80, 80, 80, 0.45);
		border-radius: 50%;
		padding: 12rpx;
	}

	/* dots */
	.dots {
		position: absolute;
		bottom: 20rpx;
		left: 50%;
		transform: translateX(-50%);
		display: flex;
	}

	.dot {
		width: 12rpx;
		height: 12rpx;
		border-radius: 50%;
		background: rgba(255, 255, 255, 0.5);
		margin: 0 6rpx;
	}

	.dot.active {
		background: #fff;
	}

	/* arrows */
	.arrow {
		position: absolute;
		top: 50%;
		transform: translateY(-50%);
		width: 60rpx;
		height: 60rpx;
		line-height: 60rpx;
		text-align: center;
		background: rgba(0, 0, 0, 0.4);
		color: #fff;
		font-size: 40rpx;
		border-radius: 50%;
	}

	.arrow.left {
		left: 20rpx;
	}

	.arrow.right {
		right: 20rpx;
	}

	/* type bar */
	.type-bar {
		position: absolute;
		bottom: 80rpx;
		left: 50%;
		transform: translateX(-50%);
		display: flex;
		height: 40rpx;
		background: rgba(0, 0, 0, 0.4);
		min-width: 300rpx;
		overflow: hidden;
		z-index: 10;
	}

	.type-segment {
		display: flex;
		justify-content: center;
		align-items: center;
		color: #fff;
		font-size: 20rpx;
		cursor: pointer;
		padding: 0 10rpx;
		transition: background 0.3s;
	}

	.type-segment.active {
		background: rgba(255, 47, 49, 0.6);
	}

	.index-display {
		position: absolute;
		bottom: 80rpx;
		right: 20rpx;
		padding: 6rpx 12rpx;
		background: rgba(0, 0, 0, 0.5);
		color: #fff;
		font-size: 24rpx;
		border-radius: 12rpx;
	}

	/* zoom */
	.zoom-overlay {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		background: rgba(0, 0, 0, 0.8);
		display: flex;
		justify-content: center;
		align-items: center;
		z-index: 999;
	}

	.zoom-img {
		max-width: 100%;
		max-height: 100%;
	}
</style>