<!-- 轮盘（一级圆盘 + 二级左半弧滚动盘）-->
<template>
	<view class="draw-all">
		<!-- 摄像头 -->
		<view class="carmera">
			<image class="all-size" src="/static/index/watch/camera.png" />
		</view>

		<!-- 轮子背景 -->
		<view class="roll">
			<image class="all-size" src="/static/index/watch/panzi.png" />
		</view>

		<!-- 一级转盘 -->
		<view ref="compass" class="compass-container" @touchstart.stop.prevent="onTouchStart"
			@touchmove.prevent.stop="onTouchMove" @touchend.stop.prevent="onTouchEnd"
			@touchcancel.stop.prevent="onTouchEnd" :style="wrapperStyle">
			<view v-for="(item, i) in items" :key="i" class="compass-item" :style="itemStyle(item.baseAngle)">
				<text :class="i===target?`item-label-target`:  `item-label`" :style="labelStyle">
					<view
						style="z-index: 2;display: flex;flex-direction: column;justify-content: center;align-items: center;">
						<image style="width: 50rpx;height: 50rpx;margin-bottom: 0rpx;"
							:class="i===target&&!opensecondmenu?`pulse`:  ``"
							:src="`/static/index/watch/Wheel/${i+1}${i===target?1:0}.png`" />
						<view :style="i===target?{color:'#fff'}:{}">
							{{ item.label }}
						</view>
					</view>
					<image class="targetimge" src="/static/index/watch/bluetarget.png"
						:style="{opacity:i===target?1:0}" />
				</text>
			</view>
		</view>

		<!-- 二级转盘 -->
		<view v-if="items2.length" ref="compass2" class="compass-container second"
			@touchstart.stop.prevent="onTouchStart2" @touchmove.prevent.stop="onTouchMove2"
			@touchend.stop.prevent="onTouchEnd2" @touchcancel.stop.prevent="onTouchEnd2" :style="wrapperStyle2"
			v-show="target !== -1">
			<view v-for="(item, i) in items2" :key="i" class="compass-item" :style="itemStyle2(item.baseAngle)">
				<text class="item-label-second" :class="i===target2&&opensecondmenu?`targetbutton`:  ``"
					:style="labelStyle2">
					<view
						style="z-index: 2;display: flex;flex-direction: column;justify-content: center;align-items: center;">
						<image style="width: 70rpx;height: 70rpx;margin-bottom: 0rpx;"
							:src="`/static/index/watch/Wheel/${target === -1 ? 0 : target+1}${i}${i===secondMapTarget[target]?1:0}.png`" />
						<view v-show="target!==-1" :style="i===secondMapTarget[target]?{color:'#0E86EA'}:{}">
							{{ item.label }}
						</view>
					</view>
				</text>
			</view>
		</view>

		<!-- 手势蒙层 -->
		<view v-if="dragging==='first'" class="gesture-mask" @touchmove.stop.prevent="onTouchMove"
			@touchend.stop.prevent="onTouchEnd" @touchcancel.stop.prevent="onTouchEnd" />
		<view v-if="dragging==='second'" class="gesture-mask" @touchmove.stop.prevent="onTouchMove2"
			@touchend.stop.prevent="onTouchEnd2" @touchcancel.stop.prevent="onTouchEnd2" />
	</view>
</template>

<script setup lang="ts">
	import { ref, reactive, onMounted, computed, nextTick, watch, onBeforeUnmount } from 'vue'

	const props = defineProps({
		opensecondmenu: {
			type: Boolean,
			default: false
		},
	})
	const emit = defineEmits(["firstIndex", "secondIndex"])
	/* ========== 基础数据 ========== */
	const labels = ['静音', '对讲', '截屏', '录制', '方位', '清晰度', '分屏', '翻转', '告警']
	const secondMapTarget = ref([1, 1, 1, 1, 1, 0, 0, 3, 1])
	const count = labels.length

	const items = reactive(labels.map((label, idx) => ({
		label,
		baseAngle: (360 / count) * idx
	})))

	/* ========== 定时器 & 常量 ========== */
	let restoreTimer : number | null = null
	let restoreTimer2 : number | null = null
	const ANIM_MS = 300
	const RESTORE_MS = 300

	/* ========== 角度状态 ========== */
	// 逻辑角（连续累积，可超过多圈）—— 由手势增量累加得到
	const currentAngle = ref(0)
	// 用于渲染到 DOM 的“显示角”，我们会对它做最短角度动画
	const displayAngle = ref(0)

	const startchange = () => {
		secondMapTarget.value[target.value] = target2.value;
		// console.log("????",target.value ,target2.value)
		if (target.value === 4 && target2.value === 0) {
			const optionSub = uni.getSubNVueById('optionSub')
			optionSub.show('fade-in')
		}else if(target.value === 4 && target2.value === 1){
			const optionSub = uni.getSubNVueById('optionSub')
			optionSub.hide('fade-out')
		}
	}


	// 拖拽状态
	const dragging = ref<null | 'first' | 'second'>(null)
	let prevTouchAngle : number | null = null
	let lastMoveDelta = 0

	let idleTimer : number | null = null
	function armIdleFinish(handler : () => void, ms = 160) {
		if (idleTimer) clearTimeout(idleTimer)
		idleTimer = setTimeout(() => { if (dragging.value) handler() }, ms) as unknown as number
	}
	function clearIdle() {
		if (idleTimer) { clearTimeout(idleTimer); idleTimer = null }
	}

	/* ========== 圆心坐标 (用于 atan2) ========== */
	const center = reactive({ x: 0, y: 0 })
	onMounted(async () => {
		await nextTick()
		uni.createSelectorQuery().select('.compass-container').boundingClientRect(rect => {
			if (rect) {
				center.x = rect.left + rect.width / 2
				center.y = rect.top + rect.height / 2
			}
		}).exec()

		// 初始对齐：用 currentAngle (0) 找到左侧项并对齐 displayAngle
		await nextTick()
		const init = getLeftmostIndexFromAngle(currentAngle.value)
		target.value = init
		// 直接把 display 对齐到 current（无动画）
		displayAngle.value = currentAngle.value
		focusIndex(init, false)
	})
	// 开启窗体
	// function chuangti() {
	// 	const optionSub = uni.getSubNVueById('optionSub')
	// 	if (target.value === 4) {
	// 		// 显示子窗体
	// 		optionSub.show('fade-in') // 第二个参数是动画时长（毫秒）
	// 	} else {
	// 		// 隐藏子窗体
	// 		optionSub.hide('fade-out')
	// 	}
	// }

	/* ========== 显示样式依赖 displayAngle ========== */
	const transitioning = ref(false)
	const wrapperStyle = computed(() => ({
		transform: `rotate(${displayAngle.value}deg)`,
		transition: transitioning.value ? `transform ${ANIM_MS}ms ease-out` : 'none'
	}))
	const labelStyle = computed(() => ({ transform: `rotate(${-displayAngle.value}deg)` }))

	function itemStyle(baseAngle : number) {
		const radius = 190
		const rad = (baseAngle * Math.PI) / 180
		const x = radius * Math.cos(rad)
		const y = radius * Math.sin(rad)
		return { transform: `translate(${x}px, ${y}px)` }
	}

	/* ========== 角度工具函数 ========== */
	function normalize360(a : number) {
		let v = a % 360
		if (v < 0) v += 360
		return v
	}
	// 返回 toAngle 相对于 fromAngle 的最短有向角差（-180,180]
	function signedShortestAngleDiff(toAngle : number, fromAngle : number) {
		// 直接利用归一化到 [0,360) 再差值并修正
		const a = normalize360(toAngle)
		const b = normalize360(fromAngle)
		let diff = a - b
		if (diff > 180) diff -= 360
		if (diff <= -180) diff += 360
		return diff
	}
	// 给出 targetAngle(0..360)，返回与 reference 最接近的等价角（可能是 target±360k）
	function chooseClosestEquivalent(targetAngle : number, reference : number) {
		const base = normalize360(targetAngle)
		let best = base
		let bestDiff = Math.abs(best - reference)
		for (let k = -3; k <= 3; k++) {
			const cand = base + k * 360
			const d = Math.abs(cand - reference)
			if (d < bestDiff) {
				bestDiff = d
				best = cand
			}
		}
		return best
	}

	/* ====== touch 角度 (标准 atan2 返回 -180..180) ====== */
	function getTouchAngle(e : TouchEvent) {
		const t = e.touches[0]
		const dx = t.clientX - center.x
		const dy = t.clientY - center.y
		return (Math.atan2(dy, dx) * 180) / Math.PI * 2
	}

	/* ========== 选中 & 恢复计时 ========== */
	const target = ref(5)
	const saveindex = ref(-1)
	function clearRestoreTimer() {
		if (restoreTimer !== null) { clearTimeout(restoreTimer); restoreTimer = null }
	}
	function startRestoreTimer() {
		clearRestoreTimer()
		restoreTimer = setTimeout(() => {
			if (target.value === -1) target.value = saveindex.value
		}, RESTORE_MS) as unknown as number
	}
	function startRestoreTimer2() {
		clearTimeout(restoreTimer2)
		restoreTimer2 = setTimeout(() => {
			if (target2.value === -1) target2.value = saveindex2.value
		}, RESTORE_MS) as unknown as number
	}

	/* ========== touch handlers：一级（使用 currentAngle 做逻辑，displayAngle 做渲染） ========== */
	function onTouchStart(e : TouchEvent) {
		saveindex.value = target.value
		target.value = -1
		transitioning.value = false
		prevTouchAngle = getTouchAngle(e)
		lastMoveDelta = 0
		dragging.value = 'first'
		startRestoreTimer()
	}
	function onTouchMove(e : TouchEvent) {
		if (prevTouchAngle === null) {
			prevTouchAngle = getTouchAngle(e); return
		}
		const angle = getTouchAngle(e)
		// 计算相对增量（短差），累加到 currentAngle（逻辑角）
		const delta = signedShortestAngleDiff(angle, prevTouchAngle as number)
		lastMoveDelta = delta
		currentAngle.value = currentAngle.value + delta
		// 直接把显示角同步到当前逻辑角（无动画）
		transitioning.value = false
		displayAngle.value = currentAngle.value
		prevTouchAngle = angle
		armIdleFinish(onTouchEnd)
		startRestoreTimer()
	}
	function onTouchEnd() {
		prevTouchAngle = null
		clearRestoreTimer()

		// 吸附到网格（snap）
		const step = 360 / count
		const snapUnit = (count % 2 === 0) ? step : step / 2

		const raw = currentAngle.value
		const snappedBase = Math.round(raw / snapUnit) * snapUnit
		const targetNorm = normalize360(snappedBase) // 0..360 的目标表示

		// 逻辑角：选择一个跟 raw 相近的等价角（保持数值连续性）
		const finalAngle = chooseClosestEquivalent(targetNorm, raw)
		// 立即把逻辑角更新为 finalAngle（这样后续逻辑以 finalAngle 为准）
		currentAngle.value = finalAngle

		// 计算显示端要动画到哪个“等价角”——选择对 displayAngle 最接近的等价角
		const displayTarget = chooseClosestEquivalent(targetNorm, displayAngle.value)

		// 计算最短差并让 displayAngle 增量变化（CSS 会走最短路径）
		let diff = displayTarget - displayAngle.value
		if (diff > 180) diff -= 360
		if (diff <= -180) diff += 360

		// 启动过渡动画
		transitioning.value = true
		displayAngle.value = displayAngle.value + diff

		// 先立刻更新 target（逻辑上的选中项）
		const leftIndex = getLeftmostIndexFromAngle(finalAngle)
		if (target.value !== leftIndex) {
			emit("firstIndex", leftIndex)
			target.value = leftIndex
		}


		// chuangti()
		// 动画结束后：关闭过渡、并用无动画方式把 displayAngle 数值对齐到逻辑角 currentAngle
		setTimeout(() => {
			transitioning.value = false
			// 把 displayAngle 对齐到 currentAngle 的数值（可能相差整圈），但无动画
			displayAngle.value = currentAngle.value
		}, ANIM_MS)

		dragging.value = null
		lastMoveDelta = 0
	}

	/* ========== focusIndex（外部调用或按钮触发的精确对齐） ========== */
	function angleForIndex(index : number) {
		if (!items[index]) return 0
		return normalize360(180 - items[index].baseAngle)
	}
	function focusIndex(index : number, animate = true) {
		if (index == null || index < 0 || index >= items.length) return
		const angle = angleForIndex(index) // 0..360 target
		// 逻辑上选择最接近 currentAngle 的等价角
		const finalAngle = chooseClosestEquivalent(angle, currentAngle.value)
		currentAngle.value = finalAngle

		// 显示端选择对 displayAngle 最接近的等价角去动画
		const displayTarget = chooseClosestEquivalent(angle, displayAngle.value)
		if (!animate) {
			transitioning.value = false
			displayAngle.value = finalAngle
			// target.value = index
			if (target.value !== index) {
				emit("firstIndex", index)
				target.value = index
			}
			return
		}

		let diff = displayTarget - displayAngle.value
		if (diff > 180) diff -= 360
		if (diff <= -180) diff += 360

		transitioning.value = true
		displayAngle.value = displayAngle.value + diff
		if (target.value !== index) {
			emit("firstIndex", index)
			target.value = index
		}

		setTimeout(() => {
			transitioning.value = false
			displayAngle.value = currentAngle.value
		}, ANIM_MS)

		dragging.value = null
	}

	/* ========== 更稳健的 getLeftmost（基于任意角度） ========== */
	function angleDiff(a : number, b : number) {
		const diff = Math.abs(normalize360(a) - normalize360(b))
		return Math.min(diff, 360 - diff)
	}
	function getLeftmostIndexFromAngle(angle : number) {
		if (!items.length) return -1
		const cur = normalize360(angle)
		let minDiff = Infinity
		let idx = 0
		items.forEach((item, i) => {
			const targetAngleForItem = normalize360(180 - item.baseAngle)
			const diff = angleDiff(cur, targetAngleForItem)
			if (diff < minDiff - 1e-9) {
				minDiff = diff
				idx = i
			}
		})
		return idx
	}
	function getLeftmostIndex() {
		return getLeftmostIndexFromAngle(currentAngle.value)
	}

	/* ================= 二级（竖向左半弧） ================ */
	const secondMapByLabel : Record<string, string[]> = {
		'静音': ['开启静音', '关闭静音',], '对讲': ['开启对讲', '关闭对讲',], '截屏': ["截屏"], '录制': ['开启录制', '关闭录制',], '方位': ['开启方位', '关闭方位',],
		'清晰度': ['高清', '流畅'],
		'分屏': ['原图', '四分屏', '180°全景', '360°全景', '环状全景'],
		'翻转': [  '左右翻转','上下翻转', '中心翻转','关闭'],
		'告警': ['开启告警', '关闭告警',]
	}

	const items2 = reactive<{ label : string; baseAngle : number }[]>([])
	const target2 = ref(0)

	const currentOffset2 = ref(0)
	const step2 = ref(0)
	const transitioning2 = ref(false)
	const DEG_PER_PX = 0.5

	const wrapperStyle2 = computed(() => ({
		transform: `rotate(${currentOffset2.value}deg)`,
		transition: transitioning2.value ? `transform 0.25s ease-out` : 'none'
	}))
	const labelStyle2 = computed(() => ({ transform: `rotate(${-currentOffset2.value}deg)` }))
	function itemStyle2(baseAngle : number) {
		const radius = 240
		const rad = (baseAngle * Math.PI) / 180
		const x = radius * Math.cos(rad)
		const y = radius * Math.sin(rad)
		return { transform: `translate(${x}px, ${y}px)` }
	}

	const presetAngles = [135, 157.5, 180, 202.5, 225]
	function getBalancedAngles(n : number) : number[] {
		const order = [2, 1, 3, 0, 4]
		return order.slice(0, n).map(i => presetAngles[i])
	}
	const minOffset2 = ref(0)
	const maxOffset2 = ref(0)
	function rebuildSecondByFirstIndex(firstIdx : number) {
		const firstLabel = items[firstIdx]?.label
		const list = (firstLabel && secondMapByLabel[firstLabel]) ? secondMapByLabel[firstLabel].slice(0, 5) : []
		const angles = getBalancedAngles(list.length)
		minOffset2.value = 180 - Math.max(...(angles.length ? angles : [180]))
		maxOffset2.value = 180 - Math.min(...(angles.length ? angles : [180]))
		items2.splice(0, items2.length)
		if (!list.length) {
			currentOffset2.value = 0
			step2.value = 0
			target2.value = -1
			return
		}
		for (let i = 0; i < list.length; i++) {
			items2.push({ label: list[i], baseAngle: angles[i] })
		}
		currentOffset2.value = 0
		step2.value = 22.5
		nextTick(() => { target2.value = getLeftmostIndex2() })
	}
	function getLeftmostIndex2() {
		if (!items2.length) return -1
		let minDiff = Infinity; let idx = 0
		items2.forEach((item, i) => {
			let real = (item.baseAngle + currentOffset2.value) % 360
			if (real < 0) real += 360
			const diff = Math.abs(real - 180)
			if (diff < minDiff) { minDiff = diff; idx = i }
		})
		return idx
	}

	watch(() => target.value, (idx) => {
		if (idx >= 0) {
			rebuildSecondByFirstIndex(idx)
			focusIndex(idx, true)
		} else {
			rebuildSecondByFirstIndex(idx)
		}
	}, { immediate: true })

	/* 二级手势 */
	let startY2 = 0
	let startOffset2 = 0
	function clamp2(val : number) { return Math.max(minOffset2.value, Math.min(maxOffset2.value, val)) }
	const saveindex2 = ref(-1)
	function onTouchStart2(e : TouchEvent) {
		saveindex2.value = target2.value
		const t = e.touches[0]
		startY2 = t.clientY
		startOffset2 = currentOffset2.value
		transitioning2.value = false
		target2.value = -1
		dragging.value = 'second'
		startRestoreTimer2()
	}
	function onTouchMove2(e : TouchEvent) {
		if (!items2.length) return
		const t = e.touches[0]
		const dy = t.clientY - startY2
		const Δ = step2.value || 1
		const raw = startOffset2 + (-dy) * DEG_PER_PX
		currentOffset2.value = clamp2(raw)
		armIdleFinish(onTouchEnd2)
		startRestoreTimer2()
	}
	function onTouchEnd2() {
		if (!items2.length) return
		const Δ = step2.value || 1
		const snapped = Math.round(currentOffset2.value / Δ) * Δ
		transitioning2.value = true
		currentOffset2.value = clamp2(snapped)

		setTimeout(() => (transitioning2.value = false), 250)
		dragging.value = null
		if (target.value !== getLeftmostIndex2()) {
			emit("secondIndex", target2.value)
			target2.value = getLeftmostIndex2()
		}

	}

	/* ========== 外部控制与清理 ========== */
	function moveFirstUp() {
		if (dragging.value === 'first') return
		const cur = getLeftmostIndex(); if (cur < 0) return
		const next = (cur - 1 + items.length) % items.length
		focusIndex(next, true);
		if (target.value !== next) {
			emit("firstIndex", next)
			target.value = next
		}
		
		// chuangti()
	}
	function moveFirstDown() {
		if (dragging.value === 'first') return
		const cur = getLeftmostIndex(); if (cur < 0) return
		const next = (cur + 1) % items.length
		focusIndex(next, true); 
		if (target.value !== next) {
			emit("firstIndex", next)
			target.value = next
		}
		// chuangti()
	}
	/* ======= 为二级盘新增外部控制（按偏移量，而不是按索引） ======= */
	function moveSecondUp() {
		if (dragging.value === 'second') return
		if (!items2.length) return
		const Δ = step2.value || 1
		// 手指向上 -> currentOffset2 增大 (onTouchMove 中也是这样：向上使 currentOffset2 增加)
		let target = currentOffset2.value + Δ
		// 把目标对齐到 step 网格并限制到 min/max
		target = Math.round(target / Δ) * Δ
		target = clamp2(target)
		transitioning2.value = true
		currentOffset2.value = target
		// 更新选中项（根据新的 offset 计算最靠近 180° 的项）
		target2.value = getLeftmostIndex2()
		emit("secondIndex", target2.value)
		
		setTimeout(() => (transitioning2.value = false), 250)
	}

	function moveSecondDown() {
		if (dragging.value === 'second') return
		if (!items2.length) return
		const Δ = step2.value || 1
		// 手指向下 -> currentOffset2 减小
		let target = currentOffset2.value - Δ
		target = Math.round(target / Δ) * Δ
		target = clamp2(target)
		transitioning2.value = true
		currentOffset2.value = target
		target2.value = getLeftmostIndex2()
		emit("secondIndex", target2.value)
		setTimeout(() => (transitioning2.value = false), 250)
	}

	defineExpose({ moveFirstUp, moveFirstDown, moveSecondUp, moveSecondDown, startchange })

	onBeforeUnmount(() => {
		if (restoreTimer !== null) clearTimeout(restoreTimer)
		if (restoreTimer2 !== null) clearTimeout(restoreTimer2)
		clearIdle()
	})
</script>

<style lang="less" scoped>
	.draw-all {
		width: 100%;
		height: 100%;
		background-color: #eff0f4;
		overflow: hidden;
		position: relative;
	}

	.carmera {
		position: absolute;
		right: 0;
		bottom: 250rpx;
		height: 600rpx;
		width: 200rpx;
		z-index: 1;
	}

	.roll {
		position: absolute;
		right: 0;
		bottom: 0rpx;
		height: 1300rpx;
		width: 650rpx;
	}

	.compass-container {
		width: 380px;
		height: 380px;
		border-radius: 50%;
		position: absolute;
		right: -65%;
		transform: translateY(-60%);
		bottom: 270rpx;
		margin: auto;
		touch-action: none;
		z-index: 9999;
	}

	.compass-item {
		position: absolute;
		top: 50%;
		left: 50%;
		width: 100px;
		height: 100px;
		margin: -50px 0 0 -50px;
		display: flex;
		align-items: center;
		justify-content: center;
	}

	.item-label {
		font-size: 25rpx;
		width: 130rpx;
		height: 130rpx;
		border-radius: 50%;
		display: flex;
		justify-content: center;
		align-items: center;
		background: linear-gradient(to bottom, #e6e7ed, #f4f5f7);
		border: 2rpx solid #fff;
		position: relative;
	}

	.item-label-target {
		font-size: 25rpx;
		width: 130rpx;
		height: 130rpx;
		border-radius: 50%;
		display: flex;
		justify-content: center;
		align-items: center;
		background: linear-gradient(to bottom, #e6e7ed, #f4f5f7);
		position: relative;
	}

	.item-label-second {
		font-size: 25rpx;
		width: 130rpx;
		height: 130rpx;
		border-radius: 50%;
		display: flex;
		justify-content: center;
		align-items: center;
		position: relative;
	}

	.all-size {
		width: 100%;
		height: 100%;
	}

	.targetimge {
		width: 150rpx;
		height: 130rpx;
		position: absolute;
		right: 0;
		top: 0;
		z-index: 1;
		transition: opacity 0.8s ease;
	}

	.compass-container.second {
		width: 480px;
		height: 480px;
		border-radius: 50%;
		position: absolute;
		right: -75%;
		transform: translateY(-70%);
		bottom: 172rpx;
		margin: auto;
		touch-action: none;
		z-index: 1;
	}

	.gesture-mask {
		position: fixed;
		left: 0;
		top: 0;
		right: 0;
		bottom: 0;
		z-index: 9999;
		background: transparent;
	}

	.pulse {
		/* 可调参数 */
		--scale: 1.8;
		--dur: 0.8s;

		animation: pulse var(--dur) ease-in-out infinite;
		transform-origin: center center;
		will-change: transform;
	}

	/* 放大到一定值再回到原始（平滑） */
	@keyframes pulse {
		0% {
			transform: scale(1);
		}

		50% {
			transform: scale(var(--scale));
		}

		100% {
			transform: scale(1);
		}
	}

	.targetbutton {
		--color: #99C9FD;
		--thick: 2px;
		--radius: 60rpx;
		--outline-offset: -10rpx;
		/* 外扩多少 */

		/* 内层虚线（你现在用的） */
		border-radius: var(--radius);
		// background-color: #ddf0ff;
		/* 内部背景 */
		animation: scalePulse 360ms cubic-bezier(.2, .8, .2, 1);
		/* 外层虚线：放在 outline（不会影响元素尺寸） */
		outline: var(--thick) dashed var(--color);
		outline-offset: var(--outline-offset);

		/* 保证文本 / 子元素在最上层 */
		position: relative;
		z-index: 1;
	}
</style>