<template>
	<div class="assets-edit-category-container">
		<el-dialog :title="isEdit ? '修改分类' : '添加分类'" v-model="isShowDialog" width="940px">
			<el-form ref="formRef" :model="ruleForm" :rules="rules" size="default" label-width="90px">
				<el-form-item label="上级分类">
					<el-cascader
						v-model="ruleForm.parentId"
						:options="categoryData"
						:props="{ checkStrictly: true, emitPath: false, value: 'id', label: 'name', children: 'children' }"
						placeholder="请选择上级分类"
						clearable
						:disabled="isEdit || isAddChild"
						class="w100"
					/>
				</el-form-item>
				<el-form-item label="分类名称" prop="name">
					<el-input v-model="ruleForm.name" placeholder="请输入分类名称" clearable />
				</el-form-item>
				<el-form-item label="排序">
					<el-input-number v-model="ruleForm.sort" :min="0" :max="999" controls-position="right" placeholder="请输入排序" class="w10" />
				</el-form-item>
				<el-form-item label="自定义属性">
					<div class="custom-attrs-table">
						<div class="table-head">
							<span class="col col-name">属性名称</span>
							<span class="col col-type">属性类型</span>
							<span class="col col-required">必填</span>
							<span class="col col-dict">字典</span>
							<span class="col col-dict-value">字典值</span>
							<span class="col col-ops">操作</span>
						</div>
						<div class="table-body">
							<div v-for="(attr, index) in ruleForm.attrs" :key="index" class="table-row">
								<div class="col col-name">
									<el-input v-if="!isDictType(attr.type)" v-model="attr.name" placeholder="请输入属性名称" clearable />
									<span v-else class="dict-name">{{ attr.name || '请选择字典' }}</span>
								</div>
								<div class="col col-type">
									<el-select v-model="attr.type" placeholder="属性类型" class="w100" @change="onAttrTypeChange(attr)">
										<el-option v-for="item in attrTypeOptions" :key="item.key" :label="item.value" :value="item.key" />
									</el-select>
								</div>
								<div class="col col-required">
									<el-switch v-model="attr.required" />
								</div>
								<div class="col col-dict">
									<el-select
										v-model="attr.name"
										placeholder="选择字典"
										class="w100"
										:disabled="!isDictType(attr.type)"
										:loading="dictLoading"
										clearable
										@change="onDictKeyChange(attr)"
									>
										<el-option
											v-for="(item, idx) in dictTypeOptions"
											:key="idx"
											:label="item.name || ''"
											:value="item.name || ''"
											:disabled="isDictOptionDisabled(item.name || '', attr)"
										/>
									</el-select>
								</div>
								<div class="col col-dict-value">
									<el-select
										v-if="isDictType(attr.type) && attr.name"
										v-model="attr.options"
										multiple
										placeholder="选择字典值"
										class="w100"
										collapse-tags
										collapse-tags-tooltip
										:max-collapse-tags="2"
									>
										<el-option
											v-for="(item, idx) in getDictValuesByType(attr.name, attr.dictType)"
											:key="idx"
											:label="item.value"
											:value="item.key"
										/>
									</el-select>
									<span v-else class="dict-placeholder">-</span>
								</div>
								<div class="col col-ops">
									<el-button type="danger" :icon="Delete" circle @click="removeAttr(index)" />
								</div>
							</div>
							<el-empty v-if="ruleForm.attrs.length === 0" description="暂无自定义属性" />
						</div>
						<div class="table-footer">
							<el-button type="primary" :icon="Plus" plain @click="addAttr">添加属性</el-button>
						</div>
					</div>
				</el-form-item>
			</el-form>
			<template #footer>
				<span class="dialog-footer">
					<el-button @click="onCancel" size="default">取 消</el-button>
					<el-button type="primary" @click="onSubmit" size="default" :loading="submitLoading">{{ isEdit ? '修 改' : '添 加' }}</el-button>
				</span>
			</template>
		</el-dialog>
	</div>
</template>

<script lang="ts">
export default {
	name: 'assetsEditCategory',
};
</script>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { Plus, Delete } from '@element-plus/icons-vue';
import { getCategoryTree, getCategory, addCategory, updateCategory, getCategoryAttrTypeOptions } from '/@/api/assets/category';
import { getDicts } from '/@/api/system/dict/data';
import { createFormDiff } from '/@/utils/diffUtils';

interface CategoryRow {
	id: string;
	name: string;
	level: number;
	options?: string[];
	sort?: number;
	children?: CategoryRow[] | null;
}

interface CustomAttr {
	name: string;
	type: string;
	required?: boolean;
	multiple?: boolean;
	options?: string[];
	sort?: number;
	dictKey?: string;
	dictValues?: string[];
	dictType?: string;
}

interface DictInfo {
	name: string;
	type: string;
	remark: string;
}

interface RuleForm {
	id: string | '';
	parentId: string;
	name: string;
	sort: number;
	attrs: CustomAttr[];
}

const emit = defineEmits(['getCategoryList']);

const formRef = ref();
const isShowDialog = ref(false);
const isEdit = ref(false);
const isAddChild = ref(false);
const submitLoading = ref(false);
const categoryData = ref<CategoryRow[]>([]);
const attrTypeOptions = ref<{ key: string; value: string }[]>([]);
const dictTypeOptions = ref<DictInfo[]>([]);
const dictValueOptions = ref<any[]>([]);
const dictLoading = ref(false);
// 使用通用工具函数保存原始数据，用于最小化传参
const categoryFormDiff = createFormDiff<Record<string, any>>();

const ruleForm = reactive<RuleForm>({
	id: '',
	parentId: '',
	name: '',
	sort: 0,
	attrs: [],
});

const rules = {
	name: [{ required: true, message: '分类名称不能为空', trigger: 'blur' }],
};

// 获取属性类型
const fetchAttrTypeOptions = () => {
	getCategoryAttrTypeOptions()
		.then((res: any) => {
			const list = res.data?.options ?? [];
			attrTypeOptions.value = list.map((item: any) => ({
				key: item.key ?? item.Key ?? '',
				value: item.value ?? item.Value ?? '',
			}));
		})
		.catch(() => {
			attrTypeOptions.value = [];
		});
};

// 获取字典类型数据
const fetchDictTypeOptions = () => {
	dictLoading.value = true;
	return getDicts('assets')
		.then((res: any) => {
			const list = res.data?.list ?? [];
			// 提取所有字典类型信息
			dictTypeOptions.value = list.map((item: any) => item.info).filter((info: DictInfo) => info && info.name);
			// 保存完整的字典数据列表（包含info和values）
			dictValueOptions.value = list;
		})
		.catch((err: any) => {
			dictTypeOptions.value = [];
			dictValueOptions.value = [];
		})
		.finally(() => {
			dictLoading.value = false;
		});
};

// 根据字典类型获取对应的字典值（优先使用 dictType 匹配）
const getDictValuesByType = (dictName: string, dictType?: string) => {
	if (!dictName && !dictType) return [];
	// 优先使用 dictType 匹配，这样即使字典名称修改也能正确匹配
	let dictItem;
	if (dictType) {
		dictItem = dictValueOptions.value.find((item: any) => item.info?.type === dictType);
	}
	// 如果 dictType 没匹配到，再用 name 匹配（兼容旧数据）
	if (!dictItem && dictName) {
		dictItem = dictValueOptions.value.find((item: any) => item.info?.name === dictName);
	}
	return dictItem?.values ?? [];
};

// 判断是否为字典类型
const isDictType = (type?: string) => type === 'select' || type === 'multi_select';

// 字典类型选择变化时
const onDictKeyChange = (attr: CustomAttr) => {
	// 清空已选的字典值
	attr.options = [];
	// 根据选择的字典名称，找到对应的 dictType 并保存
	const selectedDict = dictTypeOptions.value.find((item) => item.name === attr.name);
	attr.dictType = selectedDict?.type || '';
};

// 判断字典选项是否应被禁用
const isDictOptionDisabled = (dictName: string, currentAttr: CustomAttr) => {
	if (!dictName) return false;
	// 找到该字典对应的 type
	const dictInfo = dictTypeOptions.value.find((item) => item.name === dictName);
	const dictType = dictInfo?.type || '';
	// 检查该字典是否已被其他属性使用（使用 dictType 判断）
	return ruleForm.attrs.some(
		(attr) => attr !== currentAttr && isDictType(attr.type) && (attr.dictType === dictType || (!attr.dictType && attr.name === dictName))
	);
};

// 添加自定义属性
const addAttr = () => {
	ruleForm.attrs.push({
		name: '',
		type: 'text',
		required: true,
		options: [],
	});
};

// 删除自定义属性
const removeAttr = (index: number) => {
	ruleForm.attrs.splice(index, 1);
};

// 属性类型变化时
const onAttrTypeChange = (attr: CustomAttr) => {
	if (isDictType(attr.type)) {
		// 如果字典类型数据还没加载，则加载
		if (dictTypeOptions.value.length === 0) {
			fetchDictTypeOptions();
		}
		attr.name = '';
		attr.options = [];
	} else {
		attr.name = '';
		attr.options = [];
	}
};

onMounted(() => {
	fetchAttrTypeOptions();
});

// 重置表单
const resetForm = () => {
	ruleForm.id = '';
	ruleForm.parentId = '';
	ruleForm.name = '';
	ruleForm.sort = 0;
	ruleForm.attrs = [];
};

// 打开弹窗
const openDialog = (row?: CategoryRow | string, edit?: boolean) => {
	resetForm();
	isEdit.value = edit || false;
	isAddChild.value = false;

	// 获取分类树数据
	getCategoryTree().then((res: any) => {
		const tree = res.data?.tree ?? [];

		// 递归函数，将所有id字段转换为字符串
		const convertIdsToString = (items: any[]): any[] => {
			return items.map((item) => ({
				...item,
				id: item.id?.toString(),
				children: item.children && item.children.length > 0 ? convertIdsToString(item.children) : [],
			}));
		};

		categoryData.value = convertIdsToString(tree);
	});

	if (row && typeof row === 'object' && edit) {
		// 修改模式：获取详情
		getCategory(row.id).then((res: any) => {
			const data = res.data;
			ruleForm.id = data.id || '';
			ruleForm.parentId = data.parentId || '';
			ruleForm.name = data.name || '';
			ruleForm.sort = data.sort || 0;
			// 处理 attrs 中的 options 字段
			ruleForm.attrs = (data.attrs || []).map((attr: any) => {
				let options = attr.options;
				// 后端可能返回字符串格式，先解析
				if (typeof options === 'string') {
					try {
						options = JSON.parse(options);
					} catch {
						options = [];
					}
				}
				// 如果是对象数组 [{label, value}]，转换为简单数组 [value]
				// 这样前端选择器才能正确工作
				if (Array.isArray(options) && options.length > 0 && typeof options[0] === 'object') {
					options = options.map((opt: any) => opt.value || opt.key || opt);
				}
				return { ...attr, options: options || [] };
			});
			// 如果有单选/多选属性，预加载字典类型数据并更新字典名称
			if (ruleForm.attrs.some((attr: CustomAttr) => attr.type === 'select' || attr.type === 'multi_select')) {
				fetchDictTypeOptions().then(() => {
					// 根据 dictType 更新字典名称（字典名称可能已被修改）
					ruleForm.attrs.forEach((attr: CustomAttr) => {
						if (isDictType(attr.type) && attr.dictType) {
							const dictInfo = dictTypeOptions.value.find((item) => item.type === attr.dictType);
							if (dictInfo) {
								attr.name = dictInfo.name;
							}
						}
					});
					// 保存原始数据用于最小化传参（使用与提交相同的结构）
					categoryFormDiff.saveOriginal(JSON.parse(JSON.stringify(buildSubmitData())));
				});
			} else {
				// 保存原始数据用于最小化传参（使用与提交相同的结构）
				categoryFormDiff.saveOriginal(JSON.parse(JSON.stringify(buildSubmitData())));
			}
		});
	} else if (row && typeof row === 'string') {
		// 新增子分类模式：设置父级ID
		ruleForm.parentId = row;
		isAddChild.value = true;
	}

	isShowDialog.value = true;
};

// 关闭弹窗
const closeDialog = () => {
	isShowDialog.value = false;
};

// 取消
const onCancel = () => {
	closeDialog();
};

// 将字典值转换为 {label,value}
const formatDictOptions = (attr: CustomAttr) => {
	const options = attr.options || [];
	if (options.length > 0 && typeof options[0] === 'object') {
		return options.map((opt: any) => ({
			label: opt.label ?? opt.value ?? '',
			value: opt.value ?? opt.key ?? '',
		}));
	}
	const dictValues = getDictValuesByType(attr.name || '', attr.dictType);
	return options.map((optValue: string) => {
		const dictItem = dictValues.find((d: any) => d.key === optValue);
		return {
			label: dictItem?.value || optValue,
			value: optValue,
		};
	});
};

// 构建提交数据（用于保存原始数据和提交）
const buildSubmitData = () => {
	// 处理 attrs：统一清理脏数据
	const processedAttrs = ruleForm.attrs.map((attr) => {
		const base = {
			type: attr.type,
			required: attr.required ?? false,
			multiple: attr.type === 'multi_select',
			sort: attr.sort ?? 0,
		};

		if (isDictType(attr.type)) {
			return {
				...base,
				name: attr.name || '',
				dictType: attr.dictType || '',
				options: formatDictOptions(attr),
			};
		}

		return {
			...base,
			name: (attr.name || '').trim(),
			options: [],
		};
	});

	return {
		id: ruleForm.id,
		parentId: ruleForm.parentId ?? '',
		name: ruleForm.name,
		sort: ruleForm.sort,
		attrs: processedAttrs,
	};
};

// 提交
const onSubmit = () => {
	formRef.value.validate((valid: boolean) => {
		if (valid) {
			submitLoading.value = true;
			const submitData = buildSubmitData();

			if (isEdit.value) {
				// 编辑模式：通过 _originalData 让拦截器自动处理最小化传参
				const originalData = categoryFormDiff.getOriginal();
				const requestData = {
					...submitData,
					_originalData: originalData,
				};

				updateCategory(requestData)
					.then(() => {
						ElMessage.success('修改成功');
						closeDialog();
						emit('getCategoryList');
					})
					.finally(() => {
						submitLoading.value = false;
					});
			} else {
				// 新增模式：不传id
				const { id, ...rest } = submitData;
				addCategory(rest)
					.then(() => {
						ElMessage.success('添加成功');
						closeDialog();
						emit('getCategoryList');
					})
					.finally(() => {
						submitLoading.value = false;
					});
			}
		}
	});
};

// 暴露方法
defineExpose({
	openDialog,
});
</script>

<style scoped lang="scss">
.w100 {
	width: 100%;
}

.custom-attrs-table {
	width: 100%;
	box-sizing: border-box;
	border: 1px solid #ebeef5;
	border-radius: 6px;
	overflow: hidden;
	background: #fff;
	padding: 4px 0 0;

	.table-head,
	.table-row {
		display: grid;
		grid-template-columns: 1.4fr 1fr 80px 1fr 1.4fr 60px;
		align-items: center;
		column-gap: 12px;
		padding: 12px 16px;
	}

	.table-head {
		background: #f7f9fc;
		font-weight: 600;
		color: #4b4f58;
		.col {
			justify-content: flex-start;
			white-space: nowrap;
		}
		border-bottom: 1px solid #ebeef5;
	}

	.table-body {
		max-height: 260px;
		overflow-y: auto;
		padding: 0 16px 12px;
	}

	.table-row + .table-row {
		border-top: 1px solid #f2f2f2;
	}

	.col {
		display: flex;
		align-items: center;
		justify-content: flex-start;
	}

	.col-ops {
		justify-content: center;

		:deep(.el-button) {
			display: inline-flex;
			align-items: center;
			justify-content: center;
			margin: 0 auto;
		}

		:deep(.el-button.is-circle) {
			width: 32px;
			height: 32px;
			padding: 0;
		}

		:deep(.el-button .el-icon) {
			margin: 0;
			display: flex;
			align-items: center;
			justify-content: center;
			width: 100%;
			height: 100%;
		}

		:deep(.el-button .el-icon svg) {
			margin: 0;
		}
	}

	.col-name {
		.dict-name {
			display: inline-block;
			width: 100%;
			padding: 0 12px;
			height: 32px;
			line-height: 32px;
			border: 1px solid #dcdfe6;
			border-radius: 4px;
			color: #606266;
			background-color: #f5f7fa;
		}
	}

	.col-type,
	.col-dict,
	.col-dict-value {
		:deep(.el-select),
		:deep(.el-input) {
			width: 100%;
		}

		:deep(.el-input__wrapper) {
			width: 100%;
			box-sizing: border-box;
		}
	}

	.col-dict-value {
		min-height: 40px;

		.dict-placeholder {
			color: #c0c4cc;
		}
	}

	:deep(.el-empty) {
		padding: 24px 0;
	}

	.table-footer {
		padding: 12px 16px;
		border-top: 1px solid #ebeef5;
		text-align: left;
		background: #fafafa;
		display: flex;
		justify-content: flex-start;
	}
}
</style>
