<template>
	<a-form ref="formRef" :model="modelValue" v-bind="config" validate-trigger="blur">
		<template v-for="(item, index) in showItems" :key="index">
			<slot v-if="item.config" :name="'before-' + item.config.name" :index="index" />
			<form-item-render
				v-if="item.group === 'form' && item.config"
				:value="modelValue[item.config?.name]"
				:item="item"
				v-bind="getListeners(item.config?.name)"
				:disabled="disabled(item.config?.name)"
				@update:value="onUpdateValue($event, item)"
			>
				<template v-for="key in slotKeys" :key="key" #[key]>
					<template v-if="key">
						<slot :name="key" />
					</template>
				</template>
			</form-item-render>
			<auxiliary-item-render v-else-if="item.group === 'auxiliary'" :item="item"></auxiliary-item-render>
			<div v-else-if="item.group === 'layout' && item.type === FormItemTypeEnum.ROW">
				<a-row v-bind="Object.assign({}, $attrs, item.properties)">
					<a-col v-for="(c, i) in item.children" :key="i" v-bind="Object.assign({}, $attrs, c.properties)">
						<template v-for="child in c.children" :key="child">
							<slot v-if="child.config" :name="'before-' + child.config.name" :index="index" />
							<form-item-render
								v-if="child.group === 'form' && child.config && !hidden(child.config?.name)"
								:value="modelValue[child.config?.name]"
								:item="child"
								v-bind="getListeners(child.config?.name)"
								:disabled="disabled(child.config?.name)"
								@update:value="onUpdateValue($event, child)"
							>
								<template v-for="key in slotKeys" :key="key" #[key]>
									<template v-if="key">
										<slot :name="key" />
									</template>
								</template>
							</form-item-render>
							<auxiliary-item-render v-else-if="child.group === 'auxiliary'" :item="child"></auxiliary-item-render>
							<slot v-if="child.config" :name="'after-' + child.config.name" :index="index" />
						</template>
					</a-col>
				</a-row>
			</div>
			<slot v-if="item.config" :name="'after-' + item.config.name" :index="index" />
		</template>
	</a-form>
</template>
<script lang="ts" setup>
	import { PropType, computed, toRefs, useAttrs, useSlots } from 'vue'
	import AuxiliaryItemRender from './auxiliary-item-render.vue'
	import FormItemRender from './form-item-render.vue'
	import { FormConfig, FormItem, FormItemTypeEnum, FormValueType } from './form-render-types'
	import { FormInstance } from 'ant-design-vue'
	import { NamePath } from 'ant-design-vue/es/form/interface'

	const props = defineProps({
		items: {
			type: Array as PropType<FormItem[]>,
			required: true,
		},
		config: {
			type: Object as PropType<FormConfig>,
			required: true,
		},
		modelValue: {
			type: Object as PropType<Record<string, FormValueType>>,
			required: true,
		},
		disabledFields: {
			type: Array as PropType<Array<string>>,
			required: false,
			default: () => {
				return []
			},
		},
		// 要隐藏的表单项
		hiddenFields: {
			type: Array as PropType<Array<string>>,
			required: false,
			default: () => {
				return []
			},
		},
	})

	const emit = defineEmits<{
		'update:model-value': [value: Record<string, FormValueType>]
	}>()

	const { items, config, modelValue, hiddenFields, disabledFields } = toRefs(props)

	const showItems = computed(() => {
		return items.value.filter((item) => {
			return !hiddenFields.value.includes(item.config?.name ?? '')
		})
	})

	const hidden = (name: string) => {
		return hiddenFields.value.findIndex((item) => item === name) >= 0
	}
	const disabled = (name: string) => {
		return disabledFields.value.findIndex((item) => item === name) >= 0
	}

	const attrs: Record<string, unknown> = useAttrs()
	const getListeners = (name: string) => {
		const listeners: Record<string, unknown> = {}
		for (const key in attrs) {
			// 字段名首字母大写，并加上前缀 "on"
			const nemaFixed = name.length ? name.slice(1) : ''
			const fixedName = 'on' + (name ? name.slice(0, 1).toUpperCase() + nemaFixed : '')
			if (key.startsWith(fixedName)) {
				const newEventName = key.replace(fixedName, '')
				if (newEventName) {
					listeners['on' + newEventName] = attrs[key]
				}
			}
		}
		return listeners
	}

	const onUpdateValue = (value: FormValueType, item: FormItem) => {
		nextTick(() => {
			validateFields([item.config?.name ?? ''])
		})
		emit('update:model-value', { ...modelValue.value, ...{ [item.config?.name ?? '']: value } })
	}

	const slotKeys = computed(() => {
		let keys: string[] = []
		for (const k in useSlots()) {
			keys = keys.concat([k])
		}
		return keys
	})
	const formRef = ref<FormInstance>()

	// 校验表单
	const validateFields = (nameList?: Array<NamePath>) => {
		if (!formRef.value) {
			throw new Error('获取 formRef 失败')
		}
		return formRef.value.validateFields(nameList).catch((err) => {
			console.log(err)
			return Promise.reject(err)
		})
	}
	// 重置校验
	const clearValidate = async (nameList?: NamePath) => {
		if (!formRef.value) {
			throw new Error('获取 formRef 失败')
		}
		return formRef.value?.clearValidate(nameList)
	}
	// 重置表单
	const resetFields = async () => {
		emit('update:model-value', modelValue.value)
		formRef.value?.clearValidate()
	}
	defineExpose({ validateFields, resetFields, clearValidate })
</script>
