/**
 * 差异比较工具函数
 * 用于编辑时最小化传参，只传递修改过的字段
 */

/**
 * 深度比较两个值是否相等
 * @param val1 值1
 * @param val2 值2
 * @returns 是否相等
 */
export function isEqual(val1: any, val2: any): boolean {
	// 处理 null 和 undefined
	if (val1 === val2) return true;
	if (val1 == null || val2 == null) return val1 == val2;

	// 处理基本类型
	if (typeof val1 !== 'object' || typeof val2 !== 'object') {
		return val1 === val2;
	}

	// 处理数组
	if (Array.isArray(val1) && Array.isArray(val2)) {
		if (val1.length !== val2.length) return false;
		return val1.every((item, index) => isEqual(item, val2[index]));
	}

	// 处理对象
	if (Array.isArray(val1) !== Array.isArray(val2)) return false;

	const keys1 = Object.keys(val1);
	const keys2 = Object.keys(val2);
	if (keys1.length !== keys2.length) return false;

	return keys1.every((key) => isEqual(val1[key], val2[key]));
}

/**
 * 比较两个对象，返回差异部分
 * @param original 原始数据
 * @param current 当前数据
 * @param options 配置选项
 * @returns 差异数据对象
 */
export function getChangedFields<T extends Record<string, any>>(
	original: T,
	current: T,
	options?: {
		/** 需要包含的字段（即使没有变化也会包含） */
		alwaysInclude?: string[];
		/** 需要排除的字段（即使有变化也不会包含） */
		exclude?: string[];
		/** 字段值转换器，用于提交前转换值 */
		transformers?: Record<string, (value: any) => any>;
	}
): Partial<T> {
	const { alwaysInclude = [], exclude = [], transformers = {} } = options || {};
	const changed: Partial<T> = {};

	// 遍历当前数据的所有字段
	const allKeys = new Set([...Object.keys(original), ...Object.keys(current)]);

	allKeys.forEach((key) => {
		// 排除指定字段
		if (exclude.includes(key)) return;

		const originalValue = original[key];
		const currentValue = current[key];

		// 检查是否需要始终包含
		if (alwaysInclude.includes(key)) {
			const value = transformers[key] ? transformers[key](currentValue) : currentValue;
			(changed as any)[key] = value;
			return;
		}

		// 比较值是否变化
		if (!isEqual(originalValue, currentValue)) {
			const value = transformers[key] ? transformers[key](currentValue) : currentValue;
			(changed as any)[key] = value;
		}
	});

	return changed;
}

/**
 * 创建一个用于保存和比较表单数据的工具
 * @returns 工具对象
 */
export function createFormDiff<T extends Record<string, any>>() {
	let originalData: T | null = null;

	return {
		/**
		 * 保存原始数据
		 * @param data 原始数据
		 */
		saveOriginal(data: T) {
			// 深拷贝保存原始数据
			originalData = JSON.parse(JSON.stringify(data));
		},

		/**
		 * 获取原始数据
		 * @returns 原始数据
		 */
		getOriginal(): T | null {
			return originalData;
		},

		/**
		 * 获取变化的字段
		 * @param current 当前数据
		 * @param options 配置选项
		 * @returns 差异数据对象
		 */
		getChanges(
			current: T,
			options?: {
				alwaysInclude?: string[];
				exclude?: string[];
				transformers?: Record<string, (value: any) => any>;
			}
		): Partial<T> {
			if (!originalData) {
				// 如果没有原始数据，返回所有当前数据
				return { ...current };
			}
			return getChangedFields(originalData, current, options);
		},

		/**
		 * 检查是否有变化
		 * @param current 当前数据
		 * @param exclude 排除的字段
		 * @returns 是否有变化
		 */
		hasChanges(current: T, exclude?: string[]): boolean {
			if (!originalData) return true;
			const changes = getChangedFields(originalData, current, { exclude });
			return Object.keys(changes).length > 0;
		},

		/**
		 * 重置原始数据
		 */
		reset() {
			originalData = null;
		},
	};
}
