<template>
	<view class="page-select-mask" v-if="modelValue" @click="onClose" @touchmove.stop.prevent>
		<view class="page-select-container" @click.stop @touchmove.stop>
			<!-- 标题栏 -->
			<view class="select-header">
				<text class="select-title">{{ title }}</text>
				<view class="close-btn" @click="onClose">
					<view class="line line1"></view>
					<view class="line line2"></view>
				</view>
			</view>

			<!-- 搜索栏（可选） -->
			<view class="search-bar" v-if="searchable">
				<view class="search-box">
					<view class="search-icon"></view>
					<input class="search-input" v-model="localSearchKey" :placeholder="searchPlaceholder" @confirm="onSearch" confirm-type="search" />
					<view class="search-btn" @click="onSearch">查询</view>
				</view>
			</view>

			<!-- 列表区 -->
			<view class="select-list-wrapper" @touchmove.stop>
				<scroll-view scroll-y class="select-list" @scrolltolower="onScrollBottom" lower-threshold="80">
					<view class="select-list-inner">
						<view
							v-for="(item, index) in options"
							:key="index"
							class="select-item"
							:class="{ 'active': isSelected(item) }"
							@click="onSelect(item)"
						>
							<!-- 默认插槽：自定义每行内容 -->
							<slot name="item" :item="item" :index="index">
								<text class="item-label">{{ getLabel(item) }}</text>
							</slot>
							<!-- 选中对勾 -->
							<view class="checkmark" v-if="isSelected(item)"></view>
						</view>
						<view class="loading-tip" v-if="loading">加载中...</view>
						<view class="no-more-tip" v-else-if="finished && options.length > 0">没有更多了</view>
						<view class="empty-tip" v-if="options.length === 0 && !loading">{{ emptyText }}</view>
					</view>
				</scroll-view>
			</view>
		</view>
	</view>
</template>

<script setup>
/**
 * 分页选择器组件（纯 UI，不涉及网络调用）
 * 支持搜索 + 滑动到底部触发分页
 * @Author: Antigravity
 */
import { ref, watch } from 'vue'

const props = defineProps({
	modelValue: Boolean,
	title: { type: String, default: '请选择' },
	options: { type: Array, default: () => [] },
	value: { type: [String, Number], default: '' },
	labelKey: { type: String, default: 'label' },
	valueKey: { type: String, default: 'value' },
	loading: { type: Boolean, default: false },
	finished: { type: Boolean, default: true },
	searchable: { type: Boolean, default: false },
	searchKey: { type: String, default: '' },
	searchPlaceholder: { type: String, default: '请输入关键词搜索' },
	emptyText: { type: String, default: '暂无选项' }
})

const emit = defineEmits(['update:modelValue', 'select', 'loadMore', 'search'])

const localSearchKey = ref(props.searchKey)

watch(() => props.searchKey, (val) => { localSearchKey.value = val })

const getLabel = (item) => {
	if (typeof item === 'string' || typeof item === 'number') return item
	return item[props.labelKey]
}

const getValue = (item) => {
	if (typeof item === 'string' || typeof item === 'number') return item
	return item[props.valueKey]
}

const isSelected = (item) => getValue(item) === props.value

const onSelect = (item) => {
	emit('select', item)
	emit('update:modelValue', false)
}

const onClose = () => {
	emit('update:modelValue', false)
}

const onScrollBottom = () => {
	if (!props.loading && !props.finished) {
		emit('loadMore')
	}
}

const onSearch = () => {
	emit('search', localSearchKey.value)
}
</script>

<style lang="scss" scoped>
.page-select-mask {
	position: fixed;
	top: 0; left: 0; right: 0; bottom: 0;
	background: rgba(0, 0, 0, 0.6);
	display: flex;
	align-items: center;
	justify-content: center;
	z-index: 9999;
	backdrop-filter: blur(2px);
}

.page-select-container {
	width: 620rpx;
	background: #fff;
	border-radius: 32rpx;
	display: flex;
	flex-direction: column;
	max-height: 70vh;
	overflow: hidden;
	animation: popIn 0.25s ease-out;
}

@keyframes popIn {
	from { transform: scale(0.8); opacity: 0; }
	to { transform: scale(1); opacity: 1; }
}

.select-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 32rpx 40rpx;
	border-bottom: 2rpx solid #f2f2f2;

	.select-title {
		font-size: 32rpx;
		font-weight: bold;
		color: #333;
	}
}

.close-btn {
	width: 40rpx;
	height: 40rpx;
	position: relative;

	.line {
		position: absolute;
		top: 50%; left: 50%;
		width: 30rpx; height: 4rpx;
		background: #999;
		border-radius: 4rpx;
	}
	.line1 { transform: translate(-50%, -50%) rotate(45deg); }
	.line2 { transform: translate(-50%, -50%) rotate(-45deg); }
}

.search-bar {
	padding: 20rpx 32rpx;
	border-bottom: 2rpx solid #f2f2f2;
}

.search-box {
	display: flex;
	align-items: center;
	background: #f5f5f5;
	border-radius: 36rpx;
	padding: 0 24rpx;
	height: 72rpx;

	.search-icon {
		width: 20rpx; height: 20rpx;
		border: 3rpx solid #999;
		border-radius: 50%;
		margin-right: 12rpx;
		position: relative;

		&::after {
			content: '';
			width: 10rpx; height: 3rpx;
			background: #999;
			position: absolute;
			bottom: -4rpx; right: -4rpx;
			transform: rotate(45deg);
		}
	}

	.search-input {
		flex: 1;
		font-size: 26rpx;
	}

	.search-btn {
		font-size: 26rpx;
		color: #ff9500;
		font-weight: bold;
		margin-left: 20rpx;
	}
}

.select-list-wrapper {
	flex: 1;
	min-height: 0;
	overflow: hidden;
}

.select-list {
	max-height: 55vh;
}

.select-list-inner {
	padding: 0 32rpx;
}

.select-item {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 30rpx 0;
	border-bottom: 2rpx solid #f9f9f9;

	&:active { background: #f7f8fa; }

	&.active .item-label { color: #ff9500; font-weight: bold; }

	.item-label { font-size: 28rpx; color: #333; flex: 1; }
}

.checkmark {
	width: 12rpx; height: 22rpx;
	border-right: 4rpx solid #ff9500;
	border-bottom: 4rpx solid #ff9500;
	transform: rotate(45deg);
	flex-shrink: 0;
}

.loading-tip, .no-more-tip {
	padding: 30rpx 0;
	text-align: center;
	color: #bbb;
	font-size: 24rpx;
}

.empty-tip {
	padding: 80rpx 0;
	text-align: center;
	color: #ccc;
	font-size: 26rpx;
}
</style>
