<template>
	<view class="overlay" :style="modelStyle" @touchmove.stop.prevent v-if="showGuide">
		<view class="overlay-part" ref="overlayPartTop" :animation="overlayPartTop"
			:style="{ height: `${hole.top}px`,transform:`translateY(${-hole.top}px)`}"></view>
		<view class="middle-row">
			<view class="overlay-part" ref="overlayPartLeft" :animation="overlayPartLeft"
				:style="{ width: `${hole.left}px`, height: `${hole.height}px`,transform:`translateX(${-hole.left}px)`}">
			</view>
			<view class="hole" :style="{ width: `${hole.width}px`, height: `${hole.height}px` }" @click="handler">
			</view>
			<view class="overlay-part" ref="overlayPartRight" :animation="overlayPartRight"
				:style="{ width: `${screenWidth - hole.left - hole.width}px`, height: `${hole.height}px`,transform:`translateX(${screenWidth - hole.left - hole.width}px)`}">
			</view>
		</view>
		<view class="overlay-part" ref="overlayPartBottom" :animation="overlayPartBottom"
			:style="{ height: `${screenHeight - hole.top - hole.height}px`,transform:`translateY(${screenHeight - hole.top - hole.height}px)`}">
		</view>


		<!-- tips提示框 -->
		<view class="tips" ref="tips" :style="{opacity:isTips?1:0,...tipPosition}">
			<text class="text">{{ guideInfo.tips }}</text>
			<view class="tool-btn">
				<text @click="skip" class="text">跳过</text>
				<view class="next" style="" @click="next">
					<text class="text">{{ guideInfo.next }}</text>
				</view>
			</view>
			<view class="arrow" :style="arrowPosition"></view>
		</view>
	</view>
</template>

<script>
	// #ifdef APP-NVUE
	const dom = weex.requireModule("dom");
	const animationModule = weex.requireModule('animation')
	// #endif
	export default {
		data() {
			return {
				stepName: 'step', //该提示步骤的名称，用于不在重复展示
				isTips: false,
				isStop: false,
				guideList: [{
					el: '',
					tips: '',
					next: '',
				}],
				overlayPartTop: {},
				overlayPartLeft: {},
				overlayPartRight: {},
				overlayPartBottom: {},
				tipsAction: {},
				index: 0, // 当前展示的索引
				showGuide: false, // 是否显示引导
				tipPosition: {},
				arrowPosition: '',
				// 屏幕宽高
				screenWidth: 0,
				screenHeight: 0,
				// 洞的动态位置和尺寸
				hole: {
					top: 0, // 距顶部距离
					left: 0, // 距左侧距离
					width: 0, // 洞的宽度
					height: 0, // 洞的高度
				}
			};
		},
		computed: {
			guideInfo() {
				return this.guideList[this.index] || {};
			},
			modelStyle() {
				const style = {
					width: this.screenWidth + 'px',
					height: this.screenHeight + 'px',
				}
				return style;
			},
		},
		mounted() {
			const systemInfo = uni.getSystemInfoSync();
			const guide = uni.getStorageSync(this.stepName);
			this.$nextTick(() => {
				this.screenWidth = systemInfo.windowWidth;
				this.screenHeight = systemInfo.windowHeight;
			})

		},
		methods: {
			handler() {
				this.$emit('clickChunk', this.index)
			},
			async skip() {
				this.isTips = false;
				await this.closeActives()
				this.showGuide = false;
			},
			async next() {
				if (!this.guideList[this.index] || this.isStop) return;
				this.isTips = false;
				this.index++
				this.getDomInfo()
			},
			start(step) {
				this.guideList = step.guideList;
				this.stepName = step.name;
				this.showGuide = true;
				this.getDomInfo();
			},
			checkEl(el) {
				return new Promise((resolve) => {
					this.getComponentRect(el)
						.then(rect => {
							if ((rect.top + rect.height + 100) > this.screenHeight) {

								this.scrollToElement(el, rect.top).then(() => {
									resolve()
								})
							} else {
								resolve()
							}
						})
						.catch(() => {
							resolve()
						})
				})
			},
			getDomInfo() {
				this.$nextTick(async () => {
					const {
						el
					} = this.guideInfo;
					this.isStop = true;
					await this.closeActives()
					await this.checkEl(el)
					const rect = await this.getComponentRect(el)
					if (!rect) return;
					for (let key in rect) {
						this.hole[key] = rect[key] = Math.round(rect[key]);
					}
					await this.openActives()
					this.isTips = true;
					this.$nextTick(() => {
						this.viewTips()
					})
				})
			},
			animationActive(actives) {
				// console.log(actives);
				return new Promise((resolve) => {
					let count = 0;
					// #ifdef APP-NVUE
					for (let active of actives) {
						animationModule.transition(active.dom, {
							styles: active.styles || {},
							duration: active.duration,
							timingFunction: active.timingFunction,
							delay: active.delay || 0,
							transformOrigin: active.transformOrigin,
						}, () => {
							count++
							if (count >= actives.length) {
								resolve()
							}
						})
					}
					// #endif
					// #ifndef APP-NVUE
					for (let active of actives) {
						let animation = uni.createAnimation({
							duration: active.duration,
							delay: active.delay || 0,
							timingFunction: active.timingFunction,
							transformOrigin: active.transformOrigin,
						})
						let res = this.extractTransformValue(active.styles.transform)
						let args = res.value.split(',')
						animation[res.key](...args).step()
						this[active.dom] = animation.export()
					}
					setTimeout(() => {
						resolve()
					}, 500)
					// #endif

				})
			},
			extractTransformValue(transformString) {
				// 正则表达式：匹配 translateY(或 translateX( 等形式
				const regex = /([a-zA-Z]+)\(([^)]+)\)/;
				const match = transformString.match(regex);

				if (match) {
					// match[1] 是 key（如 translateY），match[2] 是括号内的内容（如 1000px）
					let value = match[2];
					return {
						key: match[1], // 提取关键字（如 translateY）
						value: value // 转换为数字（例如 1000）
					};
				}
			},

			async closeActives() {
				const duration = 500;
				const actives = [{
						// #ifdef APP-NVUE
						dom: this.$refs.overlayPartTop,
						// #endif
						// #ifndef APP-NVUE
						dom: 'overlayPartTop',
						// #endif
						styles: {
							transform: `translateY(-1000px)`,
						},
						transformOrigin: 'center center',
						timingFunction: 'ease',
						duration,
					},
					{
						// #ifdef APP-NVUE
						dom: this.$refs.overlayPartBottom,
						// #endif
						// #ifndef APP-NVUE
						dom: 'overlayPartBottom',
						// #endif
						styles: {
							transform: `translateY(1000px)`,
						},
						transformOrigin: 'center center',
						timingFunction: 'ease',
						duration,
					},
					{
						// #ifdef APP-NVUE
						dom: this.$refs.overlayPartLeft,
						// #endif
						// #ifndef APP-NVUE
						dom: 'overlayPartLeft',
						// #endif
						styles: {
							transform: `translateX(-1000px)`,
						},
						transformOrigin: 'center center',
						timingFunction: 'ease',
						duration,
					},
					{
						// #ifdef APP-NVUE
						dom: this.$refs.overlayPartRight,
						// #endif
						// #ifndef APP-NVUE
						dom: 'overlayPartRight',
						// #endif
						styles: {
							transform: `translateX(1000px)`,
						},
						transformOrigin: 'center center',
						timingFunction: 'ease',
						duration,
					}
				]
				await this.animationActive(actives)
			},
			async openActives() {
				const duration = 800;
				const actives = [{
						// #ifdef APP-NVUE
						dom: this.$refs.overlayPartTop,
						// #endif
						// #ifndef APP-NVUE
						dom: 'overlayPartTop',
						// #endif

						styles: {
							transform: `translateY(0px)`,
						},
						transformOrigin: 'center center',
						timingFunction: 'ease',
						duration,
					},
					{
						// #ifdef APP-NVUE
						dom: this.$refs.overlayPartBottom,
						// #endif
						// #ifndef APP-NVUE
						dom: 'overlayPartBottom',
						// #endif
						styles: {
							transform: `translateY(0px)`,
						},
						transformOrigin: 'center center',
						timingFunction: 'ease',
						duration,
					},
					{
						// #ifdef APP-NVUE
						dom: this.$refs.overlayPartLeft,
						// #endif
						// #ifndef APP-NVUE
						dom: 'overlayPartLeft',
						// #endif

						styles: {
							transform: `translateX(0px)`,
						},
						transformOrigin: 'center center',
						timingFunction: 'ease',
						duration,
					},
					{
						// #ifdef APP-NVUE
						dom: this.$refs.overlayPartRight,
						// #endif
						// #ifndef APP-NVUE
						dom: 'overlayPartRight',
						// #endif
						styles: {
							transform: `translateX(0px)`,
						},
						transformOrigin: 'center center',
						timingFunction: 'ease',
						duration,
					}
				]
				await this.animationActive(actives)
			},
			async viewTips() {
				if (this.hole) {
					// 如果dom宽度大于或者等于窗口宽度,需要重新调整dom展示宽度

					const index = this.index;
					// 步骤条展示的高度需要加上屏幕滚动的高度

					// 设置提示框高度
					let tipTop = this.hole.top + this.hole.height + 5; // 调小高度，避免位置太低
					// 如果dom在屏幕底部的话，重新调整提示框和三角形的定位
					let newHeight = this.screenHeight - this.hole.bottom;

					let arrowTop = -5;
					let arrowLeft = 5;
					// #ifdef APP-NVUE
					const rect = await this.getComponentRect(this.$refs.tips)
					// #endif
					// #ifndef APP-NVUE
					const rect = await this.getComponentRect('.tips')
					// #endif
					if (!rect) return;
					for (let key in rect) {
						rect[key] = rect[key] = Math.round(rect[key])
					}
					arrowLeft = (rect.width - 10) / 2;
					let holeLeft = this.hole.width / 2 + this.hole.left
					let tipLeft = holeLeft - rect.width / 2;
					// 计算 下面高度小于tips的高度 tips应该显示在上面（默认显示在下面）
					if ((this.hole.top + this.hole.height + rect.height) > this.screenHeight) {
						tipTop = this.hole.top - (rect.height + 15);
						arrowTop = rect.height - 5;
					}
					// 计算tips在遮罩层里的左右位置
					if (tipLeft < 0) {
						tipLeft = this.hole.left;
						// 计算三角形在tips里的左右位置
						arrowLeft = (this.hole.width - 10) / 2
					} else if ((tipLeft + rect.width) > this.screenWidth) {
						tipLeft = this.hole.left - (rect.width - this.hole.width);
						// 计算三角形在tips里的左右位置
						let s = (rect.width - this.hole.width);
						arrowLeft = ((rect.width - s - 10) / 2) + s;
					}
					// 设置提示框定位
					this.arrowPosition = `top:${arrowTop}px;left:${arrowLeft}px;`;
					// #ifndef APP-NVUE
					this.tipPosition = {
						top: `${tipTop  + 5}px`,
						left: `${tipLeft}px`,
					};
					// #endif
					// #ifdef APP-NVUE
					await this.animationActive([{
						dom: this.$refs.tips,
						styles: {
							transform: `translate(${tipLeft}px,${tipTop  + 5}px)`,
							opacity: 1
						},
						duration: 500,
						timingFunction: 'ease',
						transformOrigin: 'center center',
						needLayout: true
					}])
					// #endif
					this.isStop = false;
				}
			},
			scrollToElement(el, top) {
				return new Promise((resolve, reject) => {
					if (!el) {
						reject('el is not defind')
						return;
					}
					// #ifdef APP-NVUE
					if (dom) {
						dom.scrollToElement(el, {
							offset: this.screenHeight / 2,
							animated: true
						})
						setTimeout(() => {
							resolve()
						}, 500)
					} else {
						reject('dom module is not defind')
					}
					// #endif


					// #ifndef APP-NVUE
					const fn = () => {
						setTimeout(() => {
							resolve()
						}, 500)
					}
					this.$emit('scrollToElement', {
						top,
						fn
					})
					// #endif
				})
			},
			getComponentRect(el) {
				return new Promise((resolve, reject) => {
					if (!el) {
						reject('el is not defind')
						return;
					}
					// #ifdef APP-NVUE
					if (dom) {
						dom.getComponentRect(el, (option) => {

							if (option.result) {
								resolve(option.size)
							} else {
								console.log('获取元素Rect失败', option);
								reject(option.size)
							}
						});
					} else {
						reject('dom module is not defind')
					}
					// #endif
					// #ifndef APP-NVUE
					try {
						console.log('元神启动3', el);
						uni.createSelectorQuery().in(this.$root)
							.select(el).boundingClientRect(option => {
								console.log('元神启动4', option);
								resolve(option)
							}).exec();
					} catch (e) {
						//TODO handle the exception
						reject(e)
					}
					// #endif
				})
			},
		}
	};
</script>

<style lang="scss" scoped>
	.overlay {
		position: fixed;
		top: 0;
		left: 0;
		z-index: 1000;

		.overlay-part {
			background-color: rgba(33, 33, 33, 0.5);
		}

		.middle-row {
			display: flex;
			flex-direction: row;
		}

		.hole {
			background-color: transparent;
		}

		.tips {
			width: 400rpx;
			box-shadow: 0px 2px 9px 0px rgba(0, 0, 0, 0.1);
			position: absolute;
			top: 0rpx;
			left: 0rpx;
			padding: 15rpx 20rpx;
			border-radius: 12rpx;
			background: linear-gradient(180deg, #1cbbb4, #0081ff);
			/* #ifndef APP-NVUE */
			transition: all ease 0.2s;
			/* #endif */
			z-index: 1000;

			.text {
				font-size: 28rpx;
				color: #fff;
			}

			.tool-btn {
				display: flex;
				flex-direction: row;
				justify-content: space-between;
				align-items: center;
				padding-right: 0rpx;
				margin-top: 20rpx;

				.text {
					color: #666;
					line-height: 48rpx;
					font-size: 24rpx;
					text-align: center;
				}

				.next {
					background: #fff;
					height: 48rpx;
					width: 100rpx;
					border-radius: 8rpx;

					.text {
						color: #666;
						line-height: 48rpx;
						font-size: 24rpx;
						text-align: center;
					}
				}
			}

			.arrow {
				height: 20rpx;
				width: 20rpx;
				background: #1cbbb4;
				position: absolute;
				top: -10rpx;
				transform: rotate(45deg);
			}
		}
	}
</style>