import type { Upload } from './Upload';

// 定义ASCII码中的空格和逗号字符的码点
const ASCII_SPACE = ' '.codePointAt(0);
const ASCII_COMMA = ','.codePointAt(0);
// 定义用于验证Base64字符串的正则表达式
const BASE64_REGEX = /^[\d+/A-Za-z]*={0,2}$/;

/**
 * 验证元数据键的有效性
 * @param key 需要验证的键
 * @returns 如果键有效则返回true，否则返回false
 */
export function validateKey(key: string) {
	// 如果键的长度为0，则无效
	if (key.length === 0) {
		return false;
	}

	// 遍历键的每个字符，检查其码点是否在有效范围内
	for (let i = 0; i < key.length; ++i) {
		const charCodePoint = key.codePointAt(i) as number;
		if (
			charCodePoint > 127 || // 非ASCII字符
			charCodePoint === ASCII_SPACE || // 空格字符
			charCodePoint === ASCII_COMMA // 逗号字符
		) {
			return false;
		}
	}

	return true;
}

/**
 * 验证元数据值的有效性
 * @param value 需要验证的值
 * @returns 如果值是有效的Base64字符串则返回true，否则返回false
 */
export function validateValue(value: string) {
	// Base64字符串的长度必须是4的倍数
	if (value.length % 4 !== 0) {
		return false;
	}

	// 使用正则表达式验证Base64字符串的格式
	return BASE64_REGEX.test(value);
}

/**
 * 解析元数据字符串
 * @param str 需要解析的元数据字符串
 * @returns 返回解析后的元数据对象
 * @throws 如果元数据字符串无效则抛出错误
 */
export function parse(str?: string) {
	const meta: Record<string, string | null> = {};

	// 如果字符串为空或仅包含空白字符，则无效
	if (!str || str.trim().length === 0) {
		throw new Error('Metadata string is not valid');
	}

	// 遍历字符串中的每个键值对
	for (const pair of str.split(',')) {
		const tokens = pair.split(' ');
		const [key, value] = tokens;
		// 验证键和值的有效性，并确保键在元数据对象中不存在
		if (
			key &&
			((tokens.length === 1 && validateKey(key)) ||
				(tokens.length === 2 && validateKey(key) && value && validateValue(value))) &&
			!(key in meta)
		) {
			// 如果值存在，则将其从Base64解码为UTF-8字符串
			const decodedValue = value ? Buffer.from(value, 'base64').toString('utf8') : null;
			meta[key] = decodedValue;
		} else {
			throw new Error('Metadata string is not valid');
		}
	}

	return meta;
}

/**
 * 将元数据对象序列化为字符串
 * @param metadata 需要序列化的元数据对象
 * @returns 返回序列化后的元数据字符串
 */
export function stringify(metadata: NonNullable<Upload['metadata']>): string {
	return Object.entries(metadata)
		.map(([key, value]) => {
			// 如果值为null，则仅返回键
			if (value === null) {
				return key;
			}

			// 将值编码为Base64字符串，并与键组合
			const encodedValue = Buffer.from(value, 'utf8').toString('base64');
			return `${key} ${encodedValue}`;
		})
		.join(',');
}
