<template>
	<div
		ref="wrapperRef"
		:class="containerKls"
		:style="containerStyle"
		@mouseenter="handleMouseEnter"
		@mouseleave="handleMouseLeave"
	>
		<div v-if="slots.prefix" :class="ns.e('prefix')">
			<slot name="prefix" />
		</div>
		<div ref="innerRef" :class="innerKls">
			<el-tag
				v-for="(item, index) in showTagList"
				:key="index"
				:size="tagSize"
				:closable="closable"
				:type="tagType"
				:effect="tagEffect"
				:draggable="closable && draggable"
				:style="tagStyle"
				disable-transitions
				@close="handleRemoveTag(index)"
				@dragstart="(event: DragEvent) => handleDragStart(event, index)"
				@dragover="(event: DragEvent) => handleDragOver(event, index)"
				@dragend="handleDragEnd"
				@drop.stop
			>
				<slot name="tag" :value="item" :index="index">
					{{ item }}
				</slot>
			</el-tag>
			<el-tooltip
				v-if="collapseTags && modelValue && modelValue.length > maxCollapseTags"
				ref="tagTooltipRef"
				:disabled="!collapseTagsTooltip"
				:fallback-placements="['bottom', 'top', 'right', 'left']"
				:effect="effect"
				placement="bottom"
			>
				<template #default>
					<div ref="collapseItemRef" :class="ns.e('collapse-tag')">
						<el-tag
							:closable="false"
							:size="tagSize"
							:type="tagType"
							:effect="tagEffect"
							disable-transitions
						>
							+ {{ modelValue.length - maxCollapseTags }}
						</el-tag>
					</div>
				</template>
				<template #content>
					<div :class="ns.e('input-tag-list')">
						<el-tag
							v-for="(item, index) in collapseTagList"
							:key="index"
							:size="tagSize"
							:closable="closable"
							:type="tagType"
							:effect="tagEffect"
							disable-transitions
							@close="handleRemoveTag(index + maxCollapseTags)"
						>
							<slot name="tag" :value="item" :index="index + maxCollapseTags">
								{{ item }}
							</slot>
						</el-tag>
					</div>
				</template>
			</el-tooltip>
			<div :class="ns.e('input-wrapper')">
				<input
					:id="inputId"
					ref="inputRef"
					v-model="inputValue"
					v-bind="attrs"
					type="text"
					:minlength="minlength"
					:maxlength="maxlength"
					:disabled="disabled"
					:readonly="readonly"
					:autocomplete="autocomplete"
					:tabindex="tabindex"
					:placeholder="placeholder"
					:autofocus="autofocus"
					:ariaLabel="ariaLabel"
					:class="ns.e('input')"
					:style="inputStyle"
					@compositionstart="handleCompositionStart"
					@compositionupdate="handleCompositionUpdate"
					@compositionend="handleCompositionEnd"
					@paste="handlePaste"
					@input="handleInput"
					@keydown="handleKeydown"
					@keyup="handleKeyup"
				/>
				<span
					ref="calculatorRef"
					aria-hidden="true"
					:class="ns.e('input-calculator')"
					v-text="inputValue"
				/>
			</div>
			<div v-show="showDropIndicator" ref="dropIndicatorRef" :class="ns.e('drop-indicator')" />
		</div>
		<div v-if="showSuffix" :class="ns.e('suffix')">
			<slot name="suffix" />
			<el-icon
				v-if="showClear"
				:class="[ns.e('icon'), ns.e('clear')]"
				@mousedown.prevent="NOOP"
				@click="handleClear"
			>
				<component :is="clearIcon" />
			</el-icon>
			<el-icon
				v-if="validateState && validateIcon && needStatusIcon"
				:class="[
					nsInput.e('icon'),
					nsInput.e('validateIcon'),
					nsInput.is('loading', validateState === 'validating')
				]"
			>
				<component :is="validateIcon" />
			</el-icon>
		</div>
	</div>
</template>

<script lang="ts" setup>
import { computed, markRaw, useSlots } from 'vue'
import { NOOP, ValidateComponentsMap } from 'element-plus/lib/utils'
import { CircleClose } from '@element-plus/icons-vue'
import {
	ElTooltip,
	ElIcon,
	ElTag,
	useFormItem,
	useFormItemInputId,
	useAttrs,
	useCalcInputWidth,
	type InputTagProps
} from 'element-plus'
import { inputTagEmits } from 'element-plus'
import {
	useDragTag,
	useHovering,
	useInputTag,
	useInputTagDom
} from 'element-plus/lib/components/input-tag/src/composables'

defineOptions({
	inheritAttrs: false
})

const props = withDefaults(defineProps<InputTagProps>(), {
	tagType: 'info',
	tagEffect: 'light',
	effect: 'light',
	trigger: 'Enter',
	delimiter: '',
	clearIcon: markRaw(CircleClose),
	disabled: undefined,
	validateEvent: true,
	id: undefined,
	tabindex: 0,
	autocomplete: 'off',
	saveOnBlur: true,
	maxCollapseTags: 1
})
const emit = defineEmits(inputTagEmits)

const attrs = useAttrs()
const slots = useSlots()
const { form, formItem } = useFormItem()
const { inputId } = useFormItemInputId(props, { formItemContext: formItem })

const needStatusIcon = computed(() => form?.statusIcon ?? false)
const validateState = computed(() => formItem?.validateState || '')
const validateIcon = computed(() => {
	return validateState.value && ValidateComponentsMap[validateState.value]
})

const {
	inputRef,
	wrapperRef,
	tagTooltipRef,
	isFocused,
	inputValue,
	size,
	tagSize,
	placeholder,
	closable,
	disabled,
	showTagList,
	collapseTagList,
	handleDragged,
	handlePaste,
	handleInput,
	handleKeydown,
	handleKeyup,
	handleRemoveTag,
	handleClear,
	handleCompositionStart,
	handleCompositionUpdate,
	handleCompositionEnd,
	focus,
	blur
} = useInputTag({ props, emit, formItem })
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering()
const { calculatorRef, inputStyle } = useCalcInputWidth()
const { dropIndicatorRef, showDropIndicator, handleDragStart, handleDragOver, handleDragEnd } =
	useDragTag({ wrapperRef, handleDragged, afterDragged: focus })
const {
	ns,
	nsInput,
	containerKls,
	containerStyle,
	innerKls,
	showClear,
	showSuffix,
	tagStyle,
	collapseItemRef,
	innerRef
} = useInputTagDom({
	props,
	hovering,
	isFocused,
	inputValue,
	disabled,
	size,
	validateState,
	validateIcon,
	needStatusIcon
})

defineExpose({
	focus,
	blur
})
</script>
