<template>
	<view v-if="visible" class="overlay" @touchmove.prevent.self>
		<view class="box" :style="boxStyle" @touchstart.stop.prevent="onDragStartTouch"
			@mousedown.stop.prevent="onDragStartMouse">
			<view class="header" ref="headerRef">
				<view class="title">{{ title }}</view>
				<view class="actions">
					<button class="btn" @click="cancel">取消</button>
					<button class="btn" @click="confirm">确定</button>
				</view>
			</view>

			<picker-view class="picker-view" :style="{
          height: pickerHeight + 'px',
          '--item-h': ITEM_H + 'px',
          '--cols': displayColumns.length || 1
        }" :value="normalizedSelectedIndexes" @change="onPickerChange">
				<picker-view-column class="picker-view-column" v-for="(col, ci) in displayColumns" :key="ci">
					<view v-for="(item, i) in col" :key="i" class="picker-item">{{ item }}</view>
					<!-- :style="{ height: ITEM_H + 'px', lineHeight: ITEM_H + 'px' }" -->
				</picker-view-column>
			</picker-view>

			<view class="resize-handle" @touchstart.stop.prevent="onResizeStartTouch"
				@mousedown.stop.prevent="onResizeStartMouse">
				<view class="grip"></view>
			</view>
		</view>
	</view>
</template>

<script setup>
	import {
		ref,
		computed,
		watch,
		onMounted,
		onBeforeUnmount,
		nextTick
	} from 'vue';

	const props = defineProps({
		modelValue: {
			type: Boolean,
			default: false
		},
		title: {
			type: String,
			default: '请选择'
		},
		initLeft: {
			type: Number,
			default: 50
		},
		initTop: {
			type: Number,
			default: 100
		},
		initWidth: {
			type: Number,
			default: 320
		},
		initHeight: {
			type: Number,
			default: 320
		},
		minWidth: {
			type: Number,
			default: 180
		},
		minHeight: {
			type: Number,
			default: 200
		},
		maxWidth: {
			type: Number,
			default: 1000
		},
		maxHeight: {
			type: Number,
			default: 1200
		},
		columns: {
			type: Array,
			default: () => [
				[]
			]
		},
		nameKey: {
			type: [String, Array],
			default: 'name'
		},
		value: {
			type: Array,
			default: () => []
		}
	});
	const emit = defineEmits(['update:modelValue', 'confirm', 'change', 'update:position', 'update:size','close']);

	/* ========== 基本可见性 / 同步 ========== */
	const visible = ref(props.modelValue);
	watch(() => props.modelValue, v => visible.value = v);
	watch(visible, v => emit('update:modelValue', v));

	/* ========== 位置 / 尺寸 ========== */
	const left = ref(props.initLeft);
	const top = ref(props.initTop);
	const width = ref(props.initWidth);
	const height = ref(props.initHeight);

	/* ========== 固定行高（关键：整数像素） ========== */
	const ITEM_H = 44; // 行高（px），保持整数像素
	const HEADER_H = 44; // header 高度（px），与你样式一致

	/* ========== selectedIndexes 初始值 & 正规化 ========== */
	const selectedIndexes = ref(
		(props.value && props.value.length) ? props.value.map(v => Number(v || 0)) : (Array.isArray(props.columns) ?
			props.columns.map(() => 0) : [])
	);
	watch(() => props.value, v => {
		if (v && v.length) {
			selectedIndexes.value = v.map(x => Number(x || 0));
			clampSelectedIndexes();
		}
	});
	const normalizedSelectedIndexes = computed(() => selectedIndexes.value.map(v => Number(v || 0)));

	/* ========== columns -> displayColumns（显示文本） ========== */
	function getByPath(obj, path) {
		if (obj == null) return undefined;
		if (!path) return obj;
		const parts = path.split('.');
		let cur = obj;
		for (let p of parts) {
			if (cur == null) return undefined;
			cur = cur[p];
		}
		return cur;
	}
	const displayColumns = computed(() => {
		const raw = props.columns || [];
		const nk = props.nameKey;
		return raw.map((col, ci) => {
			if (!Array.isArray(col)) return [];
			return col.map(item => {
				if (item == null) return '';
				if (typeof item === 'object') {
					let keyToUse = Array.isArray(nk) ? (nk[ci] !== undefined ? nk[ci] : nk[0]) :
					nk;
					if (!keyToUse) {
						return item.name ?? item.label ?? item.title ?? String(item);
					}
					const val = getByPath(item, keyToUse);
					return (val === undefined || val === null) ? (item.name ?? item.label ?? item
						.title ?? String(item)) : String(val);
				} else {
					return String(item);
				}
			});
		});
	});
	const rawColumns = computed(() => (props.columns || []).map(col => Array.isArray(col) ? col : []));

	/* ========== 屏幕信息（只用 uni.getSystemInfoSync，App/H5/小程序 均可用） ========== */
	let screenW = 800,
		screenH = 600; // 安全默认值（不会访问 window）
	onMounted(() => {
		try {
			const info = uni.getSystemInfoSync();
			// uni.getSystemInfoSync 在 App/H5/小程序 都可用，优先使用
			screenW = info.windowWidth || info.screenWidth || screenW;
			screenH = info.windowHeight || info.screenHeight || screenH;
		} catch (e) {
			// 若异常，不尝试访问 window，保留默认值
			screenW = screenW;
			screenH = screenH;
		}
	});

	/* ========== 拖拽 / 缩放（保持原逻辑） ========== */
	let dragging = false;
	let dragStart = {
		x: 0,
		y: 0,
		left: 0,
		top: 0
	};
	let resizing = false;
	let resizeStart = {
		x: 0,
		y: 0,
		w: 0,
		h: 0
	};

	function onDragStartTouch(e) {
		const t = e.touches && e.touches[0];
		if (t) startDrag(t.clientX, t.clientY);
	}

	function onDragStartMouse(e) {
		startDrag(e.clientX, e.clientY);
	}

	function startDrag(cx, cy) {
		dragging = true;
		dragStart.x = cx;
		dragStart.y = cy;
		dragStart.left = left.value;
		dragStart.top = top.value;
	}

	function onResizeStartTouch(e) {
		const t = e.touches && e.touches[0];
		if (t) startResize(t.clientX, t.clientY);
	}

	function onResizeStartMouse(e) {
		startResize(e.clientX, e.clientY);
	}

	function startResize(cx, cy) {
		resizing = true;
		resizeStart.x = cx;
		resizeStart.y = cy;
		resizeStart.w = width.value;
		resizeStart.h = height.value;
	}

	function onTouchMove(e) {
		if (!dragging && !resizing) return;
		const t = e.touches && e.touches[0];
		if (t) handleMove(t.clientX, t.clientY, e);
	}

	function onMouseMove(e) {
		if (!dragging && !resizing) return;
		handleMove(e.clientX, e.clientY, e);
	}

	function handleMove(cx, cy, e) {
		if (dragging) {
			const dx = cx - dragStart.x;
			const dy = cy - dragStart.y;
			left.value = Math.min(Math.max(0, dragStart.left + dx), Math.max(0, screenW - width.value));
			top.value = Math.min(Math.max(0, dragStart.top + dy), Math.max(0, screenH - height.value));
			emit('update:position', {
				left: left.value,
				top: top.value
			});
		} else if (resizing) {
			const dx = cx - resizeStart.x;
			const dy = cy - resizeStart.y;
			let nw = Math.min(props.maxWidth, Math.max(props.minWidth, Math.round(resizeStart.w + dx)));
			let nh = Math.min(props.maxHeight, Math.max(props.minHeight, Math.round(resizeStart.h + dy)));
			if (left.value + nw > screenW) nw = screenW - left.value;
			if (top.value + nh > screenH) nh = screenH - top.value;
			width.value = nw;
			height.value = nh;
			emit('update:size', {
				width: width.value,
				height: height.value
			});
		}
		if (e && e.preventDefault) e.preventDefault();
	}

	function onMouseUp() {
		if (dragging) dragging = false;
		if (resizing) resizing = false;
	}

	function onTouchEnd() {
		if (dragging) dragging = false;
		if (resizing) resizing = false;
	}

	/* ========== picker 行数 / 高度 计算（关键） ========== */
	const pickerHeight = computed(() => {
		const avail = Math.max(0, Math.round(height.value) - HEADER_H);
		let rows = Math.floor(avail / ITEM_H);
		if (rows < 1) rows = 1;
		if (rows % 2 === 0) rows = rows - 1 > 0 ? rows - 1 : 1;
		return rows * ITEM_H;
	});

	/* ========== clamp helper ========== */
	function clampSelectedIndexes() {
		const colsArr = rawColumns.value || [];
		if (selectedIndexes.value.length !== colsArr.length) {
			selectedIndexes.value = Array.from({
				length: colsArr.length
			}, (_, i) => selectedIndexes.value[i] ?? 0);
		}
		selectedIndexes.value = selectedIndexes.value.map((idx, ci) => {
			const col = Array.isArray(colsArr[ci]) ? colsArr[ci] : [];
			const maxIdx = Math.max(0, col.length - 1);
			return col.length ? Math.min(Math.max(0, Number(idx) || 0), maxIdx) : 0;
		});
	}

	/* ========== 对齐重置逻辑（核心） ========== */
	let resetTimer = null;

	function resetPickerAlign(delay = 40) {
		if (resetTimer) clearTimeout(resetTimer);
		resetTimer = setTimeout(() => {
			nextTick(() => {
				clampSelectedIndexes();
				selectedIndexes.value = selectedIndexes.value.map(v => Number(v || 0));
			});
			resetTimer = null;
		}, delay);
	}

	/* 在关键变化上调用重置：columns / visible / pickerHeight */
	watch(() => props.columns, () => {
		clampSelectedIndexes();
		resetPickerAlign(30);
	}, {
		deep: true,
		immediate: true
	});

	watch(() => visible.value, (v) => {
		if (v) {
			resetPickerAlign(60);
			setTimeout(() => resetPickerAlign(40), 120);
		}
	});

	watch(() => pickerHeight.value, () => {
		resetPickerAlign(30);
	});

	/* ========== picker change / confirm / cancel ========== */
	function onPickerChange(e) {
		const val = (e && e.detail && e.detail.value) ? e.detail.value : e;
		if (Array.isArray(val)) {
			selectedIndexes.value = val.map((v, ci) => {
				const col = rawColumns.value[ci] || [];
				const max = Math.max(0, col.length - 1);
				const num = Number(v) || 0;
				return col.length ? Math.min(Math.max(0, num), max) : 0;
			});
		}
		emit('change', selectedIndexes.value.slice());
		resetPickerAlign(80);
	}

	function confirm() {
		const result = selectedIndexes.value.map((idx, ci) => {
			const col = rawColumns.value[ci] || [];
			const display = (displayColumns.value[ci] && displayColumns.value[ci][idx] !== undefined) ?
				displayColumns.value[ci][idx] : (col[idx] !== undefined ? String(col[idx]) : '');
			const val = col[idx] !== undefined ? col[idx] : (display || null);
			return {
				index: idx,
				value: val,
				display
			};
		});
		emit('confirm', result);
		visible.value = false;
	}

	function cancel() {
		visible.value = false;
		emit('close');
	}

	/* ========== boxStyle ========== */
	const boxStyle = computed(() => ({
		position: 'fixed',
		left: `${Math.round(left.value)}px`,
		top: `${Math.round(top.value)}px`,
		width: `${Math.round(width.value)}px`,
		height: `${Math.round(height.value)}px`,
		zIndex: 1000,
		background: '#fff',
		borderRadius: '8px',
		boxShadow: '0 8px 24px rgba(0,0,0,0.12)',
		overflow: 'hidden',
		transform: 'translateZ(0)'
	}));

	/* ========== 全局事件监听（更稳健的平台检测） ========== */
	/* 我们优先使用 window/document（H5 环境），如果都不可用（如原生 App），则不添加全局监听，
	   因为原生 App 的触摸事件通常在组件内部就能处理（touchstart/touchmove/touchend） */
	let globalEventTarget = null;
	if (typeof window !== 'undefined' && window && typeof window.addEventListener === 'function') {
		globalEventTarget = window;
	} else if (typeof document !== 'undefined' && document && typeof document.addEventListener === 'function') {
		globalEventTarget = document;
	} else {
		globalEventTarget = null; // 在原生 App（非 H5）中通常为 null
	}

	onMounted(() => {
		if (globalEventTarget) {
			try {
				globalEventTarget.addEventListener('mousemove', onMouseMove);
				globalEventTarget.addEventListener('mouseup', onMouseUp);
				// touchmove 需要 passive:false 以阻止默认行为
				globalEventTarget.addEventListener('touchmove', onTouchMove, {
					passive: false
				});
				globalEventTarget.addEventListener('touchend', onTouchEnd);
			} catch (e) {
				// 如果某些环境不支持 options 参数，用 fallback
				try {
					globalEventTarget.addEventListener('touchmove', onTouchMove);
					globalEventTarget.addEventListener('touchend', onTouchEnd);
				} catch (err) {
					// 忽略
				}
			}
		}
	});

	onBeforeUnmount(() => {
		if (globalEventTarget) {
			try {
				globalEventTarget.removeEventListener('mousemove', onMouseMove);
				globalEventTarget.removeEventListener('mouseup', onMouseUp);
				globalEventTarget.removeEventListener('touchmove', onTouchMove);
				globalEventTarget.removeEventListener('touchend', onTouchEnd);
			} catch (e) {
				// 忽略
			}
		}
		if (resetTimer) {
			clearTimeout(resetTimer);
			resetTimer = null;
		}
	});
</script>

<style scoped>
	.overlay {
		position: fixed;
		inset: 0;
		z-index: 900;
		background: rgba(0, 0, 0, 0.35);
		display: flex;
		align-items: flex-start;
		justify-content: flex-start;
	}

	.box {
		background: #fff;
		display: flex;
		flex-direction: column;
		user-select: none;
		-webkit-user-select: none;
		transform: translateZ(0);
	}

	.header {
		height: 44px;
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 0 8px;
		border-bottom: 1px solid #eee;
		background: linear-gradient(90deg, #fff, #fafafa);
		cursor: move;
	}

	.title {
		font-size: 16px;
		font-weight: 600;
	}

	.actions {
		display: flex;
		gap: 8px;
	}

	.btn {
		padding: 6px 8px;
		border-radius: 6px;
		background: #f5f5f5;
	}

	.picker-view {
		width: 100%;
		box-sizing: border-box;
		-webkit-overflow-scrolling: touch;
		overflow: hidden;
	}

	.picker-view-column {
		display: inline-block;
		vertical-align: top;
		width: calc(100% / var(--cols, 1));
		box-sizing: border-box;
		text-align: center;
	}

	.picker-item {
		display: block;
		/* height: var(--item-h);
		line-height: var(--item-h); */
		text-align: center;
		font-size: 14px;
		box-sizing: border-box;
		user-select: none;
		-webkit-user-select: none;
		display: flex;
		justify-content: center;
		align-items: center;
	}

	.resize-handle {
		position: absolute;
		right: 6px;
		bottom: 6px;
		width: 28px;
		height: 28px;
		touch-action: none;
	}

	.grip {
		width: 100%;
		height: 100%;
		border-radius: 4px;
		border: 1px dashed #bbb;
		box-sizing: border-box;
	}
</style>