<template>
	<div class="var-select">
		<el-popover
			v-model:visible="visible"
			trigger="click"
			width="320"
			popper-class="var-select__popover"
			placement="bottom-start"
		>
			<template #reference>
				<div class="var-select__trigger">
					<el-input-tag
						:model-value="innerValue ? [innerValue] : undefined"
						placeholder="选择变量"
						aria-label="选择变量"
						clearable
						@clear="handleClear"
						@remove-tag="handleClear"
						autocomplete
						v-bind="$attrs"
					>
						<template #tag>
							<div v-if="valueInfo.type === 'env'" class="flex gap-1 items-center truncate">
								<span class="var-select__item-prefix env text-6px">
									<span>ENV</span>
								</span>
								<span class="text-gray-600">{{ valueInfo.value }}</span>
							</div>
							<div v-else-if="valueInfo.type === 'sys'" class="flex gap-1 items-center truncate">
								<span class="var-select__item-prefix sys text-6px">
									<span>SYS</span>
								</span>
								<span class="text-gray-600">{{ valueInfo.value }}</span>
							</div>
							<div v-else class="truncate" :title="valueInfo.nodeName + ' / ' + valueInfo.value">
								<span
									class="var-select__item-prefix env text-10px"
									:style="{ background: nodeMap[valueInfo?.nodeType ?? '']?.iconColor ?? '' }"
								>
									<Icon :icon="nodeMap[valueInfo?.nodeType!]?.icon!" :size="18" />
								</span>
								<span>{{ valueInfo.nodeName }}</span>
								<span class="mx-2px text-gray-400">/</span>
								<span class="text-gray-600">{{ valueInfo.value }}</span>
							</div>
						</template>
					</el-input-tag>
				</div>
			</template>

			<div class="var-select__panel">
				<el-input
					v-model="keyword"
					clearable
					size="small"
					placeholder="搜索变量"
					class="var-select__search"
				/>

				<div class="var-select__list">
					<!-- 变量列表 -->
					<div v-for="group in filteredVars" class="var-select__group">
						<div class="var-select__group-title">{{ group.name }}</div>
						<div
							v-for="item in group.variableList"
							:key="item.expression"
							class="var-select__item"
							@click="
								handleSelect({
									value: item.expression,
									type: item.type
								})
							"
						>
							<span
								class="var-select__item-prefix env text-10px"
								:style="{ background: nodeMap[group?.type ?? '']?.iconColor ?? '' }"
							>
								<span v-if="group.id === 'env'" class="text-6px">ENV</span>
								<span v-if="group.id === 'sys'" class="text-6px">SYS</span>
								<Icon v-if="group?.type" :icon="nodeMap[group?.type]?.icon!" :size="18" />
							</span>
							<span class="var-select__item-name" :title="item.name">{{ item.name }}</span>
							<span class="var-select__item-type">{{ normalizeTypeLabel(item.type) }}</span>
						</div>
					</div>

					<div v-if="!filteredVars.length" class="var-select__empty">暂无匹配的变量</div>
				</div>
			</div>
		</el-popover>
	</div>
</template>

<script setup lang="ts">
import { computed, ref, watch, inject, type Ref } from 'vue'
import { Icon } from '@repo/ui'
import { nodeMap } from '@/nodes'
import { VARIABLE_TYPE_OPTIONS } from '@/constant'

import type { NodeVar, VarType } from '@/types/var'

interface Props {
	/**
	 * 选中的变量，格式 #{xxx.var}
	 */
	modelValue: string
	/**
	 * 过滤方法
	 */
	filterFn?: (list: NodeVar[]) => NodeVar[]
}

const props = withDefaults(defineProps<Props>(), {
	modelValue: ''
})

const emit = defineEmits<{
	(e: 'update:modelValue', value: string): void
	(e: 'change', value: { value: string; type: string }): void
}>()

const nodeVars = inject<Ref<NodeVar[]>>('nodeVars')

const visible = ref(false)
const keyword = ref('')
const innerValue = ref<string>(props.modelValue)

watch(
	() => props.modelValue,
	(val) => {
		if (val !== innerValue.value) {
			innerValue.value = val
		}
	},
	{ deep: true }
)

const handleClear = () => {
	innerValue.value = ''
	emit('update:modelValue', '')
}

watch(
	() => innerValue.value,
	(val) => {
		emit('update:modelValue', val)
	},
	{ deep: true }
)

const valueInfo = computed(() => {
	// 根据#{xxx.var}解析变量
	// 解析格式 #{env.xxx} 或 #{nodeId.xxx}
	if (!innerValue.value?.startsWith('#{') || !innerValue.value?.endsWith('}')) {
		return {
			type: 'env',
			name: innerValue.value || '',
			value: innerValue.value || ''
		}
	}

	const expr = innerValue.value.slice(2, -1) // 去掉 #{ 和 }
	const [prefix, ...rest] = expr.split('.')
	const varName = rest.join('.')

	if (!prefix || !varName) {
		return {
			type: 'env',
			name: innerValue.value || '',
			value: innerValue.value || ''
		}
	}

	if (prefix === 'env') {
		// 环境变量
		return {
			type: 'env',
			name: 'env',
			value: varName
		}
	} else if (prefix.startsWith('sys')) {
		// 系统变量
		return {
			type: 'sys',
			name: 'sys',
			value: varName
		}
	} else {
		// 节点变量，需要解析节点类型名称
		if (nodeVars && Array.isArray(nodeVars.value)) {
			const node = nodeVars.value.find((item) => item.id === prefix)
			return {
				type: 'node',
				nodeType: node?.type || '',
				nodeName: node?.name || prefix,
				name: varName,
				value: varName
			}
		} else {
			return {
				type: 'node',
				nodeType: '',
				nodeName: prefix,
				name: varName,
				value: varName
			}
		}
	}
})
const normalizeTypeLabel = (type?: VarType) => {
	if (!type) return ''
	return VARIABLE_TYPE_OPTIONS.find((item) => item.value === type)?.label || ''
}

/**
 * 过滤变量列表
 */
const filteredVars = computed(() => {
	const kw = keyword.value.trim().toLowerCase()

	let list = nodeVars?.value || []
	// 先根据 filterFn 过滤一遍
	if (props.filterFn) {
		list = props.filterFn(list)
	}

	const options = list?.filter((item) => item.variableList.find((i) => i.name.includes(kw)))

	return options || []
})

const handleSelect = (variable: { value: string; type: string }) => {
	innerValue.value = variable.value
	visible.value = false
	keyword.value = ''
	emit('change', variable)
}
</script>

<style scoped lang="less">
.var-select {
	width: 100%;
	&__trigger {
		width: 100%;
		cursor: pointer;
	}
}

.var-select__popover {
	padding: 8px !important;
}

.var-select__panel {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.var-select__search {
	:deep(.el-input__wrapper) {
		box-shadow: none;
		border-radius: 8px;
		background-color: #f5f5f5;
	}
}

.var-select__list {
	max-height: 260px;
	overflow-y: auto;
}

.var-select__group + .var-select__group {
	margin-top: 8px;
	border-top: 1px solid #f2f2f2;
	padding-top: 8px;
}

.var-select__group-title {
	font-size: 12px;
	color: #999;
	margin-bottom: 4px;
}

.var-select__item {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 4px 6px;
	border-radius: 6px;
	cursor: pointer;
	font-size: 12px;
	color: #333;

	&:hover {
		background-color: #f5f7ff;
	}
}

.var-select__item-prefix {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 20px;
	height: 20px;
	border-radius: 6px;
	color: #fff;
	flex-shrink: 0;

	&.env {
		background: #6366f1;
	}

	&.sys {
		background: #f97316;
	}
}

.var-select__item-name {
	flex: 1;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.var-select__item-type {
	color: #999;
	flex-shrink: 0;
}

.var-select__empty {
	padding: 12px 4px;
	font-size: 12px;
	color: #999;
	text-align: center;
}

:deep(.el-input-tag__inner) {
	flex-wrap: nowrap;
}
</style>
