#pragma once
// emoji_detector.h - 表情符号检测

#include <cstdint>
#include <string>
#include <vector>

/**
 * @class emoji_detector
 * @brief 处理表情符号检测和序列识别
 */
class emoji_detector {
public:
	/**
	 * @brief 检查码点是否为表情符号
	 * @param in_code_point Unicode码点
	 * @return 是否是表情符号
	 */
	static bool is_emoji(uint32_t in_code_point) {
		// 常见表情符号范围检查
		if ((in_code_point >= 0x1F300 && in_code_point <= 0x1F64F) || // 表情符号
		    (in_code_point >= 0x1F680 && in_code_point <= 0x1F6FF) || // 交通与地图
		    (in_code_point >= 0x1F700 && in_code_point <= 0x1F77F) || // 符号补充
		    (in_code_point >= 0x1F780 && in_code_point <= 0x1F7FF) || // 几何形状
		    (in_code_point >= 0x1F900 && in_code_point <= 0x1F9FF) || // 补充符号与象形文字
		    (in_code_point >= 0x2600 && in_code_point <= 0x26FF)) {   // 杂项符号
			return true;
		}

		return false;
	}

	/**
	 * @brief 检查码点是否为表情序列的组件
	 * @param in_code_point Unicode码点
	 * @return 是否是表情序列组件
	 */
	static bool is_emoji_sequence_component(uint32_t in_code_point) {
		// 表情变体选择器
		if (in_code_point == 0xFE0F || in_code_point == 0xFE0E) { return true; }

		// 肤色修饰符
		if (in_code_point >= 0x1F3FB && in_code_point <= 0x1F3FF) { return true; }

		// 零宽连接符
		if (in_code_point == 0x200D) { return true; }

		return false;
	}

	/**
	 * @brief 提取表情序列
	 * @param in_text Unicode文本
	 * @param in_start_pos 开始位置
	 * @param in_out_length 输出序列长度
	 * @return 表情序列
	 */
	static std::vector<uint32_t> extract_emoji_sequence(const std::u32string& in_text, size_t in_start_pos,
	                                                    size_t&               in_out_length) {

		std::vector<uint32_t> sequence;

		if (in_start_pos >= in_text.length() || !is_emoji(in_text[in_start_pos])) {
			in_out_length = 0;
			return sequence;
		}

		// 添加基础表情符号
		sequence.push_back(in_text[in_start_pos]);
		in_out_length = 1;

		// 寻找完整序列
		size_t pos = in_start_pos + 1;
		while (pos < in_text.length()) {
			const uint32_t cp = in_text[pos];

			// 检查是否是序列组件或跟随零宽连接符的表情
			if (is_emoji_sequence_component(cp) || (pos > 0 && in_text[pos - 1] == 0x200D && is_emoji(cp))) {
				sequence.push_back(cp);
				in_out_length++;
				pos++;
			}
			else { break; }
		}

		return sequence;
	}
};
