<template>
	<view class="swiper" :style="{ backgroundColor: bgColor, height: unit(height,'px'), borderRadius: unit(radius,'px') }">
		<swiper class="wrapper" :style="{ height: unit(height,'px') }" @change="change" :circular="circular" :interval="interval" :duration="duration" :autoplay="autoplay" :current="current" :currentItemId="currentItemId" :previousMargin="previousMargin + 'px'" :nextMargin="unit(nextMargin,'px')" :acceleration="acceleration" :displayMultipleItems="displayMultipleItems" :easingFunction="easingFunction">
			<swiper-item class="item-box" v-for="(item, index) in list" :key="index">
				<view class="item-wrap" :style="[itemStyle(index)]">
					<image class="item-image" v-if="getItemType(item) === 'image'" :src="getSource(item)" :mode="imgMode" @tap="clickHandler(index)" :style="{ height: unit(height,'px'), borderRadius: unit(radius,'px') }"></image>
					<video class="item-video" v-if="getItemType(item) === 'video'" :id="`video-${index}`" :enable-progress-gesture="false" :src="getSource(item)" :poster="getPoster(item)" :title="showTitle && isObject(item) && item.title ? item.title : ''" :style="{ height: unit(height,'px') }" controls @click.stop="clickHandler(index)"></video>
					<text class="item-title" v-if="showTitle && isObject(item) && item.title && isImage(getSource(item))">{{ item.title }}</text>
				</view>
			</swiper-item>
		</swiper>
		
		<view class="indicator-wrap" :style="[addStyle(indicatorStyle)]">
			<slot name="indicator">
				<elSwiperIndicator v-if="indicator && !showTitle" :indicatorActiveColor="indicatorActiveColor" :indicatorInactiveColor="indicatorInactiveColor" :length="list.length" :current="currentIndex" :indicatorMode="indicatorMode"></elSwiperIndicator>
			</slot>
		</view>
	</view>
</template>

<script setup>
	import { computed,watch,ref,onMounted,nextTick,getCurrentInstance } from "vue";
	import { isObject,isVideo,isImage } from "../../libs/check.js";
	import { unit,px2rpx } from "../../libs/utils.js";
	import { addStyle } from "../../libs/style.js";
	import elSwiperIndicator from "./el-swiper-indicator.vue";
	
	const props = defineProps({
		// 列表数组，元素可为字符串，如为对象可通过keyName指定目标属性名
		list: {
		    type: Array,
		    default: []
		},
		// 是否显示面板指示器
		indicator: {
		    type: Boolean,
		    default: true
		},
		// 指示器非激活颜色
		indicatorActiveColor: {
		    type: String,
		    default: '#FFFFFF'
		},
		// 指示器的激活颜色
		indicatorInactiveColor: {
		    type: String,
		    default: 'rgba(255, 255, 255, 0.35)'
		},
		// 指示器样式，可通过bottom，left，right进行定位
		indicatorStyle: {
		    type: [String, Object],
		    default: ''
		},
		// 指示器模式，line-线型，dot-点型
		indicatorMode: {
		    type: String,
		    default: 'line'
		},
		// 是否自动切换
		autoplay: {
		    type: Boolean,
		    default: true
		},
		// 当前所在滑块的 index
		current: {
		    type: [String, Number],
		    default: 0
		},
		// 当前所在滑块的 item-id ，不能与 current 被同时指定
		currentItemId: {
		    type: String,
		    default: ''
		},
		// 滑块自动切换时间间隔
		interval: {
		    type: [String, Number],
		    default: 3000
		},
		// 滑块切换过程所需时间
		duration: {
		    type: [String, Number],
		    default: 300
		},
		// 播放到末尾后是否重新回到开头
		circular: {
		    type: Boolean,
		    default: false
		},
		// 前边距，可用于露出前一项的一小部分，nvue和支付宝不支持
		previousMargin: {
		    type: [String, Number],
		    default: 0
		},
		// 后边距，可用于露出后一项的一小部分，nvue和支付宝不支持
		nextMargin: {
		    type: [String, Number],
		    default: 0
		},
		// 当开启时，会根据滑动速度，连续滑动多屏，支付宝不支持
		acceleration: {
		    type: Boolean,
		    default: false
		},
		// 同时显示的滑块数量，nvue、支付宝小程序不支持
		displayMultipleItems: {
		    type: Number,
		    default: 1
		},
		// 指定swiper切换缓动动画类型，有效值：default、linear、easeInCubic、easeOutCubic、easeInOutCubic
		// 只对微信小程序有效
		easingFunction: {
		    type: String,
		    default: 'default'
		},
		// list数组中指定对象的目标属性名
		keyName: {
		    type: String,
		    default: 'url'
		},
		// 图片的裁剪模式
		imgMode: {
		    type: String,
		    default: 'aspectFill'
		},
		// 组件高度
		height: {
		    type: [String, Number],
		    default: 130
		},
		// 背景颜色
		bgColor: {
		    type: String,
		    default: '#f3f4f6'
		},
		// 组件圆角，数值或带单位的字符串
		radius: {
		    type: [String, Number],
		    default: 4
		},
		// 是否加载中
		loading: {
		    type: Boolean,
		    default: false
		},
		// 是否显示标题，要求数组对象中有title属性
		showTitle: {
		    type: Boolean,
		    default: false
		}
	});
	
	const emits   	 = defineEmits(["change","click"]);
	let currentIndex = ref(0);
	
	const itemStyle = computed(()=>{
		return index => {
			const style = {};
			// #ifndef APP-NVUE || MP-TOUTIAO
			// 左右流出空间的写法不支持nvue和头条
			// 只有配置了此二值，才加上对应的圆角，以及缩放
			if (props.nextMargin && props.previousMargin) {
				style.borderRadius = props.radius + 'rpx';
				if (index !== currentIndex.value) style.transform = 'scale(0.92)';
			}
			// #endif
			return style;
		}
	});
	
	watch(()=>props.current,(next,prev)=>{
		if(next === prev) return;
		currentIndex.value = val; // 和上游数据关联上
	});
	
	const getItemType = (item)=>{
		if (typeof item === 'string') return isVideo(getSource(item)) ? 'video' : 'image'
		if (typeof item === 'object' && props.keyName) {
			if (!item.type) return isVideo(getSource(item)) ? 'video' : 'image'
			if (item.type === 'image') return 'image'
			if (item.type === 'video') return 'video'
			return 'image'
		}
	}
	
	const getSource = (item)=>{
		if (typeof item === 'string') return item;
		if (typeof item === 'object' && props.keyName) {
			return item[props.keyName];
		}
		
		return '';
	}
	
	// 轮播切换事件
	const change = (e)=>{
		const { current } = e.detail;
		pauseVideo(currentIndex.value);
		currentIndex.value = current;
		emits('change', e.detail)
	}
	
	// 切换轮播时，暂停视频播放
	const pauseVideo = (index)=>{
		const lastItem = getSource(props.list[index])
		if (isVideo(lastItem)) {
			// 当视频隐藏时，暂停播放
			let instance = getCurrentInstance();
			const video = uni.createVideoContext(`video-${index}`, instance);
			video.pause();
		}
	}
	
	// 当一个轮播item为视频时，获取它的视频海报
	const getPoster = (item)=>{
		return typeof item === 'object' && item.poster ? item.poster : ''
	}
	
	// 点击某个item
	const clickHandler = (index)=>{
		emits('click', index)
	}
	
</script>

<style lang="scss" scoped>
	.swiper {
		display: flex;
		flex-direction: row;
		justify-content: center;
		align-items: center;
		position: relative;
		overflow: hidden;
		.wrapper {
			flex: 1;
			.item-box {
				flex: 1;
				.item-wrap {
					display: flex;
					flex-direction: row;
					position: relative;
					overflow: hidden;
					transition: transform 0.3s;
					flex: 1;
					.item-image {
						flex: 1;
					}
					.item-video {
						flex: 1;
					}
					.item-title {
						position: absolute;
						background-color: rgba(0, 0, 0, 0.3);
						bottom: 0;
						left: 0;
						right: 0;
						font-size: 28rpx;
						padding: 12rpx 24rpx;
						color: #FFFFFF;
						flex: 1;
					}
				}
			}
		}
		
		.indicator-wrap {
			position: absolute;
			bottom: 10px;
		}
	}
</style>