<template>
	<!-- 点击类目弹出的选择单（Picker） -->
	<div v-show="state.open" ref="pickerRef" class="picker" :style="{ left: state.left + 'px', top: state.top + 'px' }"
		@mousedown.stop @contextmenu.prevent>
		<div class="picker-head">
			<span>{{ state.title }}</span>
			<button class="picker-close" @click="close">×</button>
		</div>
		<div class="picker-body" v-if="state.items.length">
			<button v-for="n in state.items" :key="n" class="picker-item" @click="onPick(n)">
				{{ displayName ? displayName(n) : n }}
			</button>
		</div>
		<div v-else class="picker-empty">
			<!-- 没有可选项时的占位 -->
			{{ emptyText }}
		</div>
	</div>
</template>

<script setup lang="ts">
/**
 * 左键菜单 / Picker 抽离组件
 * - UI + 打开位置 + 点击关闭都在这里
 * - 父组件 threeDui 只调用 openAt(...)，并监听 pick 事件
 */
import { reactive, ref, onMounted, onBeforeUnmount, computed } from 'vue';

const props = defineProps<{
	/** 用于展示按钮文本（如做美化映射），可选 */
	displayName?: (name: string) => string;
	/** 空列表时的提示文案，可选 */
	emptyText?: string;
}>();

const emit = defineEmits<{
	(e: 'pick', name: string): void;
}>();

const pickerRef = ref<HTMLElement | null>(null);

const state = reactive({
	open: false,
	left: 0,
	top: 0,
	title: '' as string,
	items: [] as string[],
});

const emptyText = computed(() => props.emptyText || '暂无可选项目');

function openAt(
	x: number,
	y: number,
	payload: { title: string; items: string[] },
) {
	state.left = x;
	state.top = y;
	state.title = payload.title;
	state.items = payload.items || [];
	state.open = true;
}

function close() {
	state.open = false;
	state.items = [];
	state.title = '';
}

/** 点击选项：触发事件 + 自动关闭 */
function onPick(name: string) {
	emit('pick', name);
	close();
}

/** 点击页面空白关闭 Picker */
function onDocMousedown(ev: MouseEvent) {
	if (!state.open) {
		return;
	}
	const root = pickerRef.value;
	if (!root) {
		return;
	}
	const el = ev.target as HTMLElement;
	if (!root.contains(el)) {
		close();
	}
}

onMounted(() => {
	document.addEventListener('mousedown', onDocMousedown);
});

onBeforeUnmount(() => {
	document.removeEventListener('mousedown', onDocMousedown);
});

defineExpose({
	openAt,
	close,
});
</script>

<style scoped>
/* ========== 画布点击弹出的选择单（Picker） ========== */
.picker {
	position: absolute;
	z-index: 102;
	min-width: 220px;
	max-width: 320px;
	max-height: 50vh;
	overflow: auto;
	background: #fff;
	color: #262626;
	border: 1px solid #e5e5e5;
	border-radius: 10px;
	box-shadow: 0 8px 22px rgba(0, 0, 0, 0.18);
}

.picker-head {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 8px 10px;
	font-weight: 700;
	border-bottom: 1px solid #f0f0f0;
}

.picker-close {
	margin-left: auto;
	background: transparent;
	border: none;
	font-size: 18px;
	cursor: pointer;
}

.picker-body {
	padding: 8px;
	display: flex;
	flex-direction: column;
	gap: 6px;
}

.picker-item {
	text-align: left;
	border: 1px solid #e5e5e5;
	background: #fff;
	border-radius: 6px;
	padding: 6px 10px;
	cursor: pointer;
}

.picker-item:hover {
	background: #e6f4ff;
	border-color: #91caff;
}

.picker-empty {
	padding: 12px;
	color: #888;
}
</style>
