/// 自定义 Pattern trait，用于支持 char 和 &str 作为分隔符
/// 实现零成本抽象，编译时单态化
pub trait StrPattern {
    /// 在字符串中查找模式，返回匹配位置和模式长度
    fn find_in(&self, haystack: &str) -> Option<(usize, usize)>;
}

impl StrPattern for char {
    #[inline]
    fn find_in(&self, haystack: &str) -> Option<(usize, usize)> {
        haystack.find(*self).map(|pos| (pos, self.len_utf8()))
    }
}

impl StrPattern for &str {
    #[inline]
    fn find_in(&self, haystack: &str) -> Option<(usize, usize)> {
        haystack.find(self).map(|pos| (pos, self.len()))
    }
}

impl StrPattern for &String {
    #[inline]
    fn find_in(&self, haystack: &str) -> Option<(usize, usize)> {
        haystack.find(self.as_str()).map(|pos| (pos, self.len()))
    }
}

impl StrPattern for String {
    #[inline]
    fn find_in(&self, haystack: &str) -> Option<(usize, usize)> {
        haystack.find(self.as_str()).map(|pos| (pos, self.len()))
    }
}

pub trait StringExentd {
    /// 截取字符
    fn sub_char(&self, start_index: usize, len: usize) -> String;

    /// 截取字符为两段
    fn split_char2<P: StrPattern>(&self, lable: P) -> (String, String);

    /// 以字符分隔为数组
    fn split_char<P: StrPattern + Clone>(&self, lable: P) -> Vec<String>;

    #[deprecated(note = "请使用 split_char 方法")]
    fn split_arr<P: StrPattern + Clone>(&self, lable: P) -> Vec<String>{
        self.split_char(lable)
    }

    #[deprecated(note = "请使用 split_char2 方法")]
    fn split_two<P: StrPattern>(&self, lable: P) -> (String, String) {
        self.split_char2(lable)
    }
}

impl<T: AsRef<str>> StringExentd for T {
    /// 截取字符
    fn sub_char(&self, start_index: usize, len: usize) -> String {
        let value = self.as_ref();
        let v_len = value.chars().count();

        // 截取数据时, 验证长度够不够截取
        if v_len < start_index + len {
            return String::new();
        }

        let t = value.chars().into_iter().map(|x| x.to_string()).collect::<Vec<_>>();
        if len > t.len() {
            return "".to_owned();
        }
        let r: String = t[start_index..start_index + len].concat();
        return r;
    }
    /// 截取字符为两段
    fn split_char2<P: StrPattern>(&self, lable: P) -> (String, String) {
        let value = self.as_ref();
        let value_len = value.len();

        let (index, lable_len) = match lable.find_in(value) {
            None => return (value.to_string(), String::new()),
            Some(v) => v,
        };

        let index_start = index;
        let lable_end = index + lable_len;

        let r: String = value[0..index_start].to_string();
        let r2: String = value[lable_end..value_len].to_string();
        (r, r2)
    }

    fn split_char<P: StrPattern + Clone>(&self, lable: P) -> Vec<String> {
        let value = self.as_ref();
        let mut arr = vec![];
        let (s1, s2) = value.split_char2(lable.clone());
        arr.push(s1);
        if s2.as_str() != "" {
            let mut arr2 = s2.split_char(lable);
            arr.append(&mut arr2);
        }
        arr
    }
}

#[test]
fn test_old_sub_char() {
    // 测试字符串的字节表示
    let s = String::from("测试获得bytes");
    let expected_bytes = "测试获得bytes".as_bytes();
    assert_eq!(s.as_bytes(), expected_bytes);

    // 测试截取中英混合字符串
    let a = "郭达b欢迎你";
    let v = a.sub_char(2, 1);
    assert_eq!(v, "b");

    // 测试截取中文字符
    let a = "郭达好欢迎你";
    let v = a.sub_char(2, 1);
    assert_eq!(v, "好");

    // 测试分割字符串 - 找不到分隔符的情况
    let a = "郭达欢迎你,查找一个找不到的中文字符";
    let v = a.split_char2("好");
    assert_eq!(v, (a.to_string(), String::new()));

    // 测试分割字符串 - 找不到英文字符的情况
    let a = "郭达欢迎你,查找一个找不到的英文字符呀";
    let v = a.split_char2("e");
    assert_eq!(v, (a.to_string(), String::new()));

    // 测试分割字符串 - 找到英文字符串的情况
    let a = "郭达欢迎你,ab查找一个英文字符串";
    let v = a.split_char2(",ab");
    assert_eq!(v, ("郭达欢迎你".to_string(), "查找一个英文字符串".to_string()));

    // 测试分割字符串 - 找到中文字符串的情况
    let a = "郭达欢迎你abc,你好查找一个中文字符串";
    let v = a.split_char2("你好");
    assert_eq!(v, ("郭达欢迎你abc,".to_string(), "查找一个中文字符串".to_string()));

    // 测试分割字符串 - 找到中英混合字符串的情况
    let a = "郭达abc欢迎你,查找一个中英混和字符串";
    let v = a.split_char2("abc欢迎你,");
    assert_eq!(v, ("郭达".to_string(), "查找一个中英混和字符串".to_string()));
}

#[test]
fn test_sub_char() {
    // 测试英文字符串截取
    let a = "abcdef";
    let v = a.sub_char(0, 2);
    assert_eq!(v, "ab");

    // 测试中英混合字符串截取
    let a = "郭达abc欢迎你";
    let v = a.sub_char(0, 2);
    assert_eq!(v, "郭达");

    // 测试 String 类型的截取
    let v = String::from("郭达abc欢迎你").sub_char(0, 3);
    assert_eq!(v, "郭达a");
}

#[test]
fn test_split_char2() {
    // 测试英文字符串分割
    let a = "abcd ef";
    let v = a.split_char2("c");
    assert_eq!(v, ("ab".to_string(), "d ef".to_string()));

    // 测试中文字符串用空格分割
    let a = "郭达 欢迎你";
    let v = a.split_char2(" ");
    assert_eq!(v, ("郭达".to_string(), "欢迎你".to_string()));

    // 测试中文字符串用空格分割 (char)
    let a = "郭达 欢迎你";
    let v = a.split_char2(' ');
    assert_eq!(v, ("郭达".to_string(), "欢迎你".to_string()));

    // 测试中文字符串用中文分割
    let a = "郭达欢迎你";
    let v = a.split_char2("欢迎");
    assert_eq!(v, ("郭达".to_string(), "你".to_string()));

    // 测试找不到分隔符的情况
    let a = "郭达欢迎你";
    let v = a.split_char2("欢迎fd");
    assert_eq!(v, (a.to_string(), String::new()));

    // 测试中英混合分隔符
    let a = "郭达欢迎q你";
    let v = a.split_char2("欢迎q");
    assert_eq!(v, ("郭达".to_string(), "你".to_string()));

    // ===== 以下是 char 类型的测试 =====

    // 测试英文 char 分割
    let a = "hello-world";
    let v = a.split_char2('-');
    assert_eq!(v, ("hello".to_string(), "world".to_string()));

    // 测试英文 char 分割 - 冒号
    let a = "key:value";
    let v = a.split_char2(':');
    assert_eq!(v, ("key".to_string(), "value".to_string()));

    // 测试英文 char 分割 - 等号
    let a = "name=张三";
    let v = a.split_char2('=');
    assert_eq!(v, ("name".to_string(), "张三".to_string()));

    // 测试英文 char 分割 - 斜杠
    let a = "path/to/file";
    let v = a.split_char2('/');
    assert_eq!(v, ("path".to_string(), "to/file".to_string()));

    // 测试中文 char 分割 - 中文逗号
    let a = "你好，世界";
    let v = a.split_char2('，');
    assert_eq!(v, ("你好".to_string(), "世界".to_string()));

    // 测试中文 char 分割 - 中文顿号
    let a = "苹果、香蕉、橘子";
    let v = a.split_char2('、');
    assert_eq!(v, ("苹果".to_string(), "香蕉、橘子".to_string()));

    // 测试中文 char 分割 - 中文冒号
    let a = "姓名：李四";
    let v = a.split_char2('：');
    assert_eq!(v, ("姓名".to_string(), "李四".to_string()));

    // 测试中文 char 分割 - 单个中文字符
    let a = "前的后";
    let v = a.split_char2('的');
    assert_eq!(v, ("前".to_string(), "后".to_string()));

    // 测试找不到 char 的情况
    let a = "没有分隔符";
    let v = a.split_char2('x');
    assert_eq!(v, (a.to_string(), String::new()));

    // 测试找不到中文 char 的情况
    let a = "没有这个字";
    let v = a.split_char2('啊');
    assert_eq!(v, (a.to_string(), String::new()));
}

#[test]
fn test_split_arr() {
    // 测试英文字符串分割为数组
    let a = "abcdef";
    let v = a.split_char("c");
    assert_eq!(v, vec!["ab".to_string(), "def".to_string()]);

    // 测试中文字符串用逗号分割为数组
    let a = "郭,达欢,迎你,";
    let v = a.split_char(",");
    assert_eq!(v, vec!["郭".to_string(), "达欢".to_string(), "迎你".to_string()]);
}

#[test]
fn test_split_with_char() {
    // 测试使用 char 类型分割
    let a = "abc,def,ghi";
    let v = a.split_char(',');
    assert_eq!(v, vec!["abc".to_string(), "def".to_string(), "ghi".to_string()]);

    // 测试使用 char 类型分割中文
    let a = "郭达,欢迎,你";
    let v = a.split_char(',');
    assert_eq!(v, vec!["郭达".to_string(), "欢迎".to_string(), "你".to_string()]);

    // 测试 split_char2 使用 char
    let a = "hello world";
    let v = a.split_char2(' ');
    assert_eq!(v, ("hello".to_string(), "world".to_string()));

    // 测试使用中文 char 分割
    let a = "郭达好欢迎你";
    let v = a.split_char2('好');
    assert_eq!(v, ("郭达".to_string(), "欢迎你".to_string()));

    // 测试找不到 char 的情况
    let a = "abcdef";
    let v = a.split_char2('x');
    assert_eq!(v, ("abcdef".to_string(), String::new()));
}
