/** 常用正则，与后端校验规则保持一致 */
export const PATTERNS = {
	/** 中国大陆手机号 */
	MOBILE: /^1[3-9]\d{9}$/,
	/** 短信验证码（4-6 位数字） */
	SMS_CODE: /^\d{4,6}$/,
	/** 用户类型 */
	USER_TYPE: /^(enterprise|worker)$/,
	/** 18 位身份证号 */
	ID_CARD: /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/,
	/** 登录密码（8-64 位，含字母和数字） */
	PASSWORD: /^(?=.*[A-Za-z])(?=.*\d).{8,64}$/,
	/** 登录用户名（6-20 位，字母开头） */
	USERNAME: /^[a-zA-Z][a-zA-Z0-9_]{5,19}$/,
	/** 中文姓名（2-20 位） */
	REAL_NAME: /^[\u4e00-\u9fa5·]{2,20}$/,
	/** 银行卡号（16-19 位数字） */
	BANK_CARD: /^\d{16,19}$/,
	/** 统一社会信用代码（18 位） */
	CREDIT_CODE: /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/
}

function pass(message = '') {
	return { valid: true, message }
}

function fail(message) {
	return { valid: false, message }
}

/** 将通用校验文案替换为带字段名的提示 */
function labelize(label, message) {
	if (!label) return message

	const replacements = {
		'此项不能为空': `${label}不能为空`,
		'姓名不能为空': `${label}不能为空`,
		'请输入正确的姓名': `${label}格式不正确`,
		'身份证号不能为空': `${label}不能为空`,
		'身份证号格式不正确': `${label}格式不正确`,
		'手机号不能为空': `${label}不能为空`,
		'手机号格式不正确': `${label}格式不正确`,
		'银行卡号不能为空': `${label}不能为空`,
		'银行卡号格式不正确': `${label}格式不正确`,
		'统一社会信用代码不能为空': `${label}不能为空`,
		'统一社会信用代码格式不正确': `${label}格式不正确`,
		'验证码不能为空': `${label}不能为空`,
		'验证码格式不正确': `${label}格式不正确`,
		'密码不能为空': `${label}不能为空`,
		'密码长度为 6-20 位': `${label}长度为 6-20 位`
	}

	if (replacements[message]) return replacements[message]
	if (message.includes(label)) return message
	return `${label}：${message}`
}

function normalizeFieldConfig(config) {
	if (Array.isArray(config)) {
		return { rules: config, label: '' }
	}
	return {
		rules: config.rules || [],
		label: config.label || ''
	}
}

/** 必填 */
export function required(value, message = '此项不能为空') {
	const val = value == null ? '' : String(value).trim()
	return val ? pass() : fail(message)
}

/** 勾选必填（如协议同意） */
export function checked(value, message = '请先勾选并同意相关协议') {
	return value === true ? pass() : fail(message)
}

/** 手机号 */
export function mobile(value, message = '手机号格式不正确') {
	const check = required(value, '手机号不能为空')
	if (!check.valid) return check
	return PATTERNS.MOBILE.test(String(value).trim()) ? pass() : fail(message)
}

/** 短信验证码 */
export function smsCode(value, message = '验证码格式不正确') {
	const check = required(value, '验证码不能为空')
	if (!check.valid) return check
	return PATTERNS.SMS_CODE.test(String(value).trim()) ? pass() : fail(message)
}

const RESERVED_USERNAMES = ['admin', 'system', 'root', 'test', 'guest', 'null', 'undefined']

/** 登录密码 */
export function password(value, message = '密码须为 8-64 位且包含字母和数字') {
	const check = required(value, '密码不能为空')
	if (!check.valid) return check
	const val = String(value)
	if (val.length < 8 || val.length > 64) {
		return fail('密码须为 8-64 位')
	}
	if (!/[A-Za-z]/.test(val) || !/\d/.test(val)) {
		return fail('密码须同时包含字母和数字')
	}
	return pass()
}

/** 确认密码 */
export function confirmPassword(value, compareValue, message = '两次输入的密码不一致') {
	const check = required(value, '确认密码不能为空')
	if (!check.valid) return check
	if (String(value) !== String(compareValue)) {
		return fail(message)
	}
	return pass()
}

/** 登录用户名 */
export function username(value, message = '用户名为 6-20 位，字母开头，仅含字母、数字、下划线') {
	const check = required(value, '用户名不能为空')
	if (!check.valid) return check
	const normalized = String(value).trim().toLowerCase()
	if (!PATTERNS.USERNAME.test(normalized)) {
		return fail(message)
	}
	if (RESERVED_USERNAMES.includes(normalized)) {
		return fail('用户名不可用')
	}
	return pass()
}

/** 用户类型 */
export function userType(value, message = '用户类型不正确') {
	const check = required(value, '用户类型不能为空')
	if (!check.valid) return check
	return PATTERNS.USER_TYPE.test(String(value).trim()) ? pass() : fail(message)
}

/** 真实姓名 */
export function realName(value, message = '请输入正确的姓名') {
	const check = required(value, '姓名不能为空')
	if (!check.valid) return check
	return PATTERNS.REAL_NAME.test(String(value).trim()) ? pass() : fail(message)
}

/** 身份证号 */
export function idCard(value, message = '身份证号格式不正确') {
	const check = required(value, '身份证号不能为空')
	if (!check.valid) return check
	return PATTERNS.ID_CARD.test(String(value).trim()) ? pass() : fail(message)
}

/** 银行卡号 */
export function bankCard(value, message = '银行卡号格式不正确') {
	const check = required(value, '银行卡号不能为空')
	if (!check.valid) return check
	return PATTERNS.BANK_CARD.test(String(value).trim()) ? pass() : fail(message)
}

/** 统一社会信用代码 */
export function creditCode(value, message = '统一社会信用代码格式不正确') {
	const check = required(value, '统一社会信用代码不能为空')
	if (!check.valid) return check
	return PATTERNS.CREDIT_CODE.test(String(value).trim().toUpperCase()) ? pass() : fail(message)
}

/** 常规校验方法集合 */
export const formRules = {
	required,
	checked,
	mobile,
	smsCode,
	password,
	confirmPassword,
	username,
	userType,
	realName,
	idCard,
	bankCard,
	creditCode
}

/**
 * 执行单个字段的多条校验
 * @param {*} value 字段值
 * @param {Array<Function|string>} rules 校验函数或 formRules 中的方法名
 * @param {string} label 字段名称，用于错误提示
 * @returns {{ valid: boolean, message: string }}
 */
export function validateField(value, rules = [], label = '') {
	for (const rule of rules) {
		const validator = typeof rule === 'string' ? formRules[rule] : rule
		if (typeof validator !== 'function') continue
		const result = validator(value)
		if (!result.valid) {
			return { valid: false, message: labelize(label, result.message) }
		}
	}
	return pass()
}

/**
 * 批量校验表单
 * @param {Object} form 表单对象
 * @param {Object<string, Array<Function|string>|{ label: string, rules: Array<Function|string> }>} schema 字段校验配置
 * @returns {{ valid: boolean, message: string, field?: string }}
 *
 * @example
 * validateForm(
 *   { mobile: '13800138000', code: '123456' },
 *   {
 *     mobile: { label: '手机号', rules: ['mobile'] },
 *     code: { label: '验证码', rules: ['smsCode'] }
 *   }
 * )
 */
export function validateForm(form, schema) {
	for (const field in schema) {
		const { rules, label } = normalizeFieldConfig(schema[field])
		const result = validateField(form[field], rules, label)
		if (!result.valid) {
			return { valid: false, message: result.message, field }
		}
	}
	return { valid: true, message: '' }
}

export default formRules
