<script setup>
// TODO 实现键盘上下移动选择

import "@/lib/array.js"

// data-url 和 data-key 成对出现
import {inject, onMounted, ref} from "vue";
import useUtils from "@/utils/utils.js";
import TInputText from "@/components/ui/TInputText.vue";
import TListBox from "@/components/ui/TListBox.vue";
import TLabel from "@/components/ui/TLabel.vue";

const utils = useUtils()
const Tea = inject("$Tea")

const props = defineProps([
	"name", "title", "placeholder", "size", "v-items", "v-value",
	"data-url", // 数据源URL
	"data-key", // 数据源中数据的键名
	"data-search", // 是否启用动态搜索，如果值为on或true，则表示启用
	"width"
])
const emits = defineEmits(["change"])
const searchBox = ref()
const selectedLabel = ref()
const menu = ref()

onMounted(() => {
	if (dataURL.value.length > 0) {
		search("")
	}

	// 设定菜单宽度
	if (searchBox.value != null) {
		let inputWidth = searchBox.value.offsetWidth
		if (inputWidth != null && inputWidth > 0) {
			menu.value.style.width = inputWidth + "px"
		} else if (styleWidth.value.length > 0) {
			menu.value.style.width = styleWidth.value
		}
	}
})

const search = function (keyword) {
	// 从URL中获取选项数据
	let dataUrl = dataURL.value
	let dataKey = props.dataKey

	let requestId = Math.random()
	urlRequestId.value = requestId

	Tea.action(dataUrl)
		.params({
			keyword: (keyword == null) ? "" : keyword
		})
		.post()
		.success(function (resp) {
			if (requestId != urlRequestId.value) {
				return
			}

			if (resp.data != null) {
				if (typeof (resp.data[dataKey]) == "object") {
					let newItems = formatItems(resp.data[dataKey])
					allItems.value = newItems
					items.value = newItems.$copy()

					if (isInitial.value) {
						isInitial.value = false
						if (props.vValue != null) {
							newItems.forEach(function (v) {
								if (v.value == props.vValue) {
									selectedItem.value = v
								}
							})
						}
					}
				}
			}
		})
}

const formatItems = function (items) {
	items.forEach(function (v) {
		if (v.value == null) {
			v.value = v.id
		}
	})
	return items
}

const reset = function () {
	selectedItem.value = null
	change()
	hoverIndex.value = 0

	setTimeout(function () {
		if (searchBox) {
			searchBox.value.focus()
		}
	})
}

const clear = function () {
	if (isInitial.value) {
		selectedItem.value = null
		change()
		hoverIndex.value = 0
	}
}

const changeKeyword = function () {
	let shouldSearch = dataURL.value.length > 0 && (props.dataSearch == "on" || props.dataSearch == "true")

	hoverIndex.value = 0
	if (keyword.value.length == 0) {
		if (shouldSearch) {
			search(keyword.value)
		} else {
			items.value = allItems.value.$copy()
		}
		return
	}

	if (shouldSearch) {
		search(keyword.value)
	} else {
		items.value = allItems.value.$copy().filter(function (v) {
			if (v.fullname != null && v.fullname.length > 0 && utils.match(v.fullname, keyword.value)) {
				return true
			}
			return utils.match(v.name, keyword.value)
		})
	}
}

const selectItem = function (item) {
	selectedItem.value = item
	change()
	hoverIndex.value = 0
	keyword.value = ""
	changeKeyword()
}

const confirm = function () {
	if (items.value.length > hoverIndex.value) {
		selectItem(items.value[hoverIndex.value])
	}
}

const show = function (e) {
	visible.value = true

	// 不要重置hoverIndex，以便焦点可以在输入框和可选项之间切换
}

const hide = function () {
	hideTimer.value = setTimeout(function () {
		visible.value = false
	}, 500)
}

const downItem = function () {
	hoverIndex.value++
	if (hoverIndex.value > items.value.length - 1) {
		hoverIndex.value = 0
	}
	focusItem()
}

const upItem = function () {
	hoverIndex.value--
	if (hoverIndex.value < 0) {
		hoverIndex.value = 0
	}
	focusItem()
}

const focusItem = function () {
	if (hoverIndex.value < items.value.length) {
		//itemRef.value[hoverIndex.value].focus() // TODO
		setTimeout(function () {
			searchBox.value.focus()
			if (hideTimer.value != null) {
				clearTimeout(hideTimer.value)
				hideTimer.value = null
			}
		})
	}
}

const change = function () {
	emits("change", selectedItem.value)

	setTimeout(function () {
		if (selectedLabel.value != null) {
			selectedLabel.value.$el.focus()
		}
	})
}

const submitForm = function (event) {
	if (event.target.tagName != "A") {
		return
	}
	let parentBox = selectedLabel.value.$el.parentNode
	while (true) {
		parentBox = parentBox.parentNode
		if (parentBox == null || parentBox.tagName == "BODY") {
			return
		}
		if (parentBox.tagName == "FORM") {
			parentBox.submit()
			break
		}
	}
}

const setDataURL = function (newDataURL) {
	dataURL.value = newDataURL
}

const reloadData = function () {
	search("")
}

const {
	allItems,
	items,
	selectedItem,
	keyword,
	visible,
	hideTimer,
	hoverIndex,
	styleWidth,
	isInitial,
	dataURL,
	urlRequestId
} = (function () {
	let items = props.vItems
	if (items == null || !(items instanceof Array)) {
		items = []
	}
	items = formatItems(items)

	// 当前选中项
	let selectedItem = null
	if (props.vValue != null) {
		items.forEach(function (v) {
			if (v.value == props.vValue) {
				selectedItem = v
			}
		})
	}

	let width = props.width
	if (width == null || width.length == 0) {
		width = "11em"
	} else {
		if (/\d+$/.test(width)) {
			width += "em"
		}
	}

	// data url
	let dataURL = ""
	if (typeof props.dataUrl == "string" && props.dataUrl.length > 0) {
		dataURL = props.dataUrl
	}

	return {
		allItems: ref(items), // 原始的所有的items
		items: ref(items.$copy()), // 候选的items
		selectedItem: ref(selectedItem), // 选中的item
		keyword: ref(""),
		visible: ref(false),
		hideTimer: ref(null),
		hoverIndex: ref(0),
		styleWidth: ref(width),

		isInitial: ref(true),
		dataURL: ref(dataURL),
		urlRequestId: ref(0) // 记录URL请求ID，防止并行冲突
	}
})()

const onListItemChange = (e) => {
	selectItem(items.value.$find((k, v) => {
		return v.value == e.value
	}))
}

defineExpose({
	clear,
	setDataURL,
	reloadData
})
</script>

<template>
	<div style="display: inline; background: white" class="combo-box relative">
		<!-- 搜索框 -->
		<div v-if="selectedItem == null">
			<TInputText type="text" v-model="keyword" :placeholder="placeholder" :size="size"
						:style="{'width': styleWidth}"
						@input="changeKeyword" @focus="show" @blur="hide" @keyup.enter="confirm()"
						@keypress.enter.prevent="1" ref="searchBox" @keydown.down.prevent="downItem"
						@keydown.up.prevent="upItem"/>
		</div>

		<!-- 当前选中 -->
		<div v-if="selectedItem != null">
			<input type="hidden" :name="name" :value="selectedItem.value"/>
			<TLabel ref="selectedLabel" outlined=""><span><span
				v-if="title != null && title.length > 0">{{ title }}：</span>{{ selectedItem.name }}</span>&nbsp;
				<a href="" title="清除" @click.prevent="reset"><i class="pi pi-remove small"></i></a>
			</TLabel>
		</div>

		<!-- 菜单 -->
		<div v-show="selectedItem == null && items.length > 0 && visible" ref="menu">
			<div class="absolute bg-white z-50">
				<TListBox :options="items" @change="onListItemChange"></TListBox>
			</div>

			<!--<div class="ui menu vertical small narrow-scrollbar" ref="menu">
				<a href="" v-for="(item, index) in items" ref="itemRef" class="item"
				   :class="{active: index == hoverIndex, blue: index == hoverIndex}" @click.prevent="selectItem(item)"
				   style="line-height: 1.4">
					<span v-if="item.fullname != null && item.fullname.length > 0">{{ item.fullname }}</span>
					<span v-else>{{ item.name }}</span>
				</a>
			</div>-->
		</div>
	</div>
</template>

<style scoped>

</style>