use regex::Regex;

/// Regular expression tools, such as matching, capturing the first one, capturing all, etc.
pub struct ReUtil;

impl ReUtil {
    /// 检查文本是否匹配给定的正则表达式模式
    ///
    /// # 参数
    /// * `re` - 正则表达式模式字符串
    /// * `text` - 要检查的文本字符串
    ///
    /// # 返回值
    /// 如果文本匹配正则表达式模式则返回true，否则返回false
    ///
    /// # Panics
    /// 当正则表达式模式无效时会panic
    pub fn is_match(re: &str, text: &str) -> bool {
        // 编译正则表达式模式
        let re = Regex::new(re).unwrap();
        // 执行匹配检查
        re.is_match(text)
    }

    pub fn is_mobile(text: &str) -> bool {
        let re = Regex::new(r"^1[3456789]\d{9}$").unwrap();
        re.is_match(text)
    }

    pub fn is_email(text: &str) -> bool {
        let re = Regex::new(r"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$").unwrap();
        re.is_match(text)
    }

    pub fn is_id_card18(text: &str) -> bool {
        let re = Regex::new(r"^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$").unwrap();
        re.is_match(text)
    }

    /// 在给定文本中查找第一个匹配正则表达式的子串
    ///
    /// # 参数
    /// * `re` - 要匹配的正则表达式字符串
    /// * `text` - 要搜索的文本内容
    ///
    /// # 返回值
    /// 返回第一个匹配的子串引用，如果没有匹配则返回None
    ///
    /// # 示例
    /// ```
    /// let result = find_first(r"\d+", "abc123def456");
    /// assert_eq!(result, Some("123"));
    /// ```
    pub fn find_first<'a>(re: &str, text: &'a str) -> Option<&'a str> {
        // 编译正则表达式
        let re = Regex::new(re).unwrap();
        // 查找第一个匹配项
        if let Some(captured) = re.find(text) {
            let result = captured.as_str();
            return Some(result);
        }
        None
    }

    /// 在给定文本中查找所有匹配正则表达式的子串
    ///
    /// # 参数
    /// * `re` - 要使用的正则表达式字符串
    /// * `text` - 要搜索的文本
    ///
    /// # 返回值
    /// 返回包含所有匹配子串的字符串向量
    ///
    /// # 示例
    /// ```
    /// let matches = find_all(r"\d+", "abc123def456");
    /// assert_eq!(matches, vec!["123", "456"]);
    /// ```
    pub fn find_all(re: &str, text: &str) -> Vec<String> {
        // 编译正则表达式，如果编译失败则panic
        let re = Regex::new(re).unwrap();
        let mut vec = Vec::new();

        // 遍历所有匹配项，提取完整匹配并添加到结果向量中
        for cap in re.captures_iter(text) {
            let s = cap[0].to_string();
            vec.push(s);
        }

        vec
    }

    /// 使用正则表达式匹配文本并返回所有捕获组的字符串列表
    ///
    /// # 参数
    /// * `re` - 正则表达式字符串
    /// * `text` - 要匹配的文本字符串
    ///
    /// # 返回值
    /// 返回包含所有捕获组匹配结果的字符串向量，如果没有匹配则返回空向量
    ///
    /// # 示例
    /// ```
    /// let result = captures(r"^images_(\d{4}-\d{2}-\d{2})_([a-zA-Z0-9]+).jpg$", "images_2025-01-01_xxxx.jpg");
    /// assert_eq!(result, vec!["images_2025-01-01_xxxx.jpg", "2025-01-01", "xxxx"]);
    /// ```
    pub fn captures(re: &str, text: &str) -> Vec<String> {
        let re = Regex::new(re).unwrap();
        let mut vec = Vec::new();
        let caps = re.captures(text);

        // 遍历所有捕获组并将其转换为字符串添加到结果向量中
        if let Some(caps) = caps {
            for cap in caps.iter() {
                if let Some(cap) = cap {
                    let s = cap.as_str().to_string();
                    vec.push(s);
                }
            }
        }

        vec
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_re_util() {
        let re = r"^images_(\d{4}-\d{2}-\d{2})_([a-zA-Z0-9]+).jpg$";
        let text = "images_2025-01-01_xxxx.jpg";
        let vec = super::ReUtil::captures(re, text);
        println!("{:?}", vec);
    }
}
