<script>
export default {
	inheritAttrs: false,
}
</script>
<script setup>
// 常用属性：
//   items <Item[]> 内容条目，每个item包含{name, value}两个值
//   name <string> 字段名
//   filter <boolean> 显示选项筛选框
//   value <string|number> 默认值
//   scrollHeight <string> 滚动条高度

// 可以使用 <TSelect> <TOption value="optionValue">optionName</TOption> </TSelect> 快速添加选项

import Select from "primevue/select";
import T from "./T.js"
import {onMounted, provide, ref, watch} from "vue";

const props = defineProps({
	name: String,
	items: Array,
	optionLabel: String,
	optionValue: String,
	modelValue: null,
	value: null, // default value
	scrollHeight: ""
})

const validItems = ref([])
if (props.items !== null && props.items instanceof Array) {
	for (let item of props.items) {
		validItems.value.push(item)
	}
}

let optionLabel = props.optionLabel
if (T.isNull(optionLabel)) {
	optionLabel = "name"
}

let optionValue = props.optionValue
if (T.isNull(optionValue)) {
	optionValue = "value"
}

let scrollHeight = props.scrollHeight
if (typeof scrollHeight != "string" || scrollHeight.length == 0) {
	scrollHeight = "18rem"
}

const rootRef = ref()
const selectRef = ref()

provide("$addSelectOption", (name, value) => {
	if (!T.isNull(value)) {
		value = value.toString()
	}

	// 检查是否已经存在
	for (let item of validItems.value) {
		if (item[optionLabel] === name && item[optionValue] === value) {
			return
		}
	}

	validItems.value.push({
		[optionLabel]: name,
		[optionValue]: value
	})
})

provide("$removeSelectOption", (name, value) => {
	if (!T.isNull(value)) {
		value = value.toString()
	}

	const newValidItems = []
	for (const item of validItems.value) {
		if (item[optionLabel] === name && item[optionValue] === value) {
			continue
		}
		newValidItems.push(item)
	}
	validItems.value = newValidItems
})

provide("$updateSelectOption", (oldName, oldValue, newName, newValue) => {
	if (!T.isNull(oldValue)) {
		oldValue = oldValue.toString()
	}
	if (!T.isNull(newValue)) {
		newValue = newValue.toString()
	}

	for (const item of validItems.value) {
		if (item[optionLabel] === oldName && item[optionValue] === oldValue) {
			item[optionLabel] = newName
			item[optionValue] = newValue
			break
		}
	}

	notifyItemsChange()
})

const emits = defineEmits(["update:modelValue", "change"])
const valueRef = ref("")

watch(() => props.modelValue, (v) => {
	valueRef.value = v
})

let itemsChangeTimer
const notifyItemsChange = () => {
	if (itemsChangeTimer != null) {
		clearTimeout(itemsChangeTimer)
	}
	itemsChangeTimer = setTimeout(() => {
		if (validItems.value.length > 0) {
			if (!validItems.value.find(v => {
				return v[optionValue] == valueRef.value
			})) {
				valueRef.value = validItems.value[0][optionValue]
				emits("update:modelValue", convertValueToRawType(valueRef.value))
			}
		}
	}, 100)
}

watch(() => validItems.value, () => {
	notifyItemsChange()
})

const isScalar = (b) => {
	const t = typeof b
	return t === "number" || t === "string"
}

onMounted(() => {
	setTimeout(() => {
		if (isScalar(props.modelValue)) {
			valueRef.value = props.modelValue
			return
		}

		if (isScalar(props.value)) {
			valueRef.value = props.value
			emits("update:modelValue", convertValueToRawType(props.value))
			return
		}

		// 默认选中第一个
		let modelValue = selectRef.value.modelValue
		if (validItems.value.length > 0) {
			if ((typeof modelValue !== "string" && typeof modelValue !== "number") || !validItems.value.find(v => {
				return v[optionValue] == modelValue
			})) {
				emits("update:modelValue", convertValueToRawType(validItems.value[0][optionValue]))
				valueRef.value = validItems.value[0][optionValue]
			}
		}
	}, 15) // TODO 使用更好的方法检测子节点是否已经加载完毕

	return
})

const getOptionLabel = (value) => {
	for (const item of validItems.value) {
		if (typeof item[optionValue] === "string" && item[optionValue] === value.toString()) {
			return item[optionLabel]
		}
	}
	return ""
}

const getEmptyOptionLabel = () => {
	for (const item of validItems.value) {
		if (typeof item[optionValue] === "string" && item[optionValue].length == 0) {
			return item[optionLabel]
		}
	}
	return ""
}

const updateModelValue = v => {
	emits("update:modelValue", convertValueToRawType(v))
}

const convertValueToRawType = v => {
	if (typeof props.modelValue === "number") {
		if (v != null && v.toString().length > 0) {
			return parseInt(v) // not supported float
		}
	}
	if (typeof props.modelValue === "string") {
		if (v != null) {
			return v.toString()
		}
	}

	if (v != null) {
		return v.toString()
	}
	return v
}

const onChange = e => {
	emits("change", valueRef.value)
}

</script>

<template>
	<div ref="rootRef" class="inline-block">
		<Select ref="selectRef" :options="validItems" v-bind="$attrs" :optionLabel="optionLabel"
				:optionValue="optionValue" optionGroupLabel="" optionGroupChildren="items"
				@update:modelValue="updateModelValue" @change="onChange" :scrollHeight="scrollHeight" v-model="valueRef">
			<template #value="{value}">
				<span v-if="typeof value === 'string' || typeof value === 'number'">
					<span v-if="value.toString().length > 0">
						{{ getOptionLabel(value) }}
					</span>
					<span v-else-if="getEmptyOptionLabel().length > 0">{{ getEmptyOptionLabel() }}</span>
					<span v-else>&nbsp;</span>
					<input type="hidden" :name="name" :value="value" class="hidden"/>
				</span>
				<span v-else>&nbsp;</span>
			</template>
			<template #option="{option}">
				<span v-if="typeof option[optionLabel]=='string' && option[optionLabel].length > 0">{{ option[optionLabel] }}</span>
				<span v-else>&nbsp;</span>
			</template>
		</Select>
		<div class="hidden">
			<slot></slot>
		</div>
	</div>
</template>

<style scoped>
:global(.p-select-dropdown) {
	width: 14px !important;
	height: 14px !important;
	margin: 10px 10px;


	mask-image: var(--svg);
	--svg: url(@/assets/icon/arrow-down.svg) !important;
	background-color: currentColor !important;
	display: inline-block !important;
	-webkit-mask-size: 100% 100% !important;
	mask-size: 100% 100% !important;
	-webkit-mask-repeat: no-repeat !important;
	mask-repeat: no-repeat !important;
}

:global(.p-select-dropdown svg) {
	display: none;
}
</style>