use inpt::split::{Group, Parenthetical, Spaced, Word};
use inpt::{inpt, Inpt, InptResult};

#[test]
fn test_group() {
    type G = Vec<Group<Vec<u32>>>;
    let expected = vec![Group { inner: vec![0, 1] }, Group { inner: vec![2, 3] }];
    assert_eq!(inpt::<G>("0\n1\n\n2\n3").unwrap(), expected);
    assert_eq!(inpt::<G>("0\n1\n\n2\n3\n").unwrap(), expected);
    assert_eq!(inpt::<G>("0\n1\n\n2\n3\n\n").unwrap(), expected);
    assert_eq!(inpt::<G>("0\n1\n\n\n2\n3").unwrap(), expected);
    assert_eq!(inpt::<G>("\n0\n1\n\n2\n3").unwrap(), expected);
    assert_eq!(inpt::<G>("0\r\n1\r\n\r\n2\r\n3").unwrap(), expected);
    assert_eq!(inpt::<G>("0\r\n1\n\r\n2\r\n3\r\n").unwrap(), expected);
    assert_eq!(inpt::<G>("0\r\n1\r\n\r\n2\r\n3\r\n\r\n").unwrap(), expected);
    assert_eq!(inpt::<G>("0\r\n1\r\n\r\n\r\n2\r\n3").unwrap(), expected);
    assert_eq!(inpt::<G>("\r\n0\r\n1\r\n\r\n2\n3").unwrap(), expected);
}

#[test]
fn test_no_words() {
    inpt::<Word<&str>>("   ").unwrap_err();
}

#[test]
fn test_many_words() {
    assert!(inpt::<Vec<Word<&str>>>("  why hello.there  ")
        .unwrap()
        .into_iter()
        .map(|Word { inner }| inner)
        .eq(["why", "hello", "there"]));
}

#[test]
fn test_no_spaced() {
    inpt::<Spaced<&str>>("   ").unwrap_err();
}

#[test]
fn test_many_spaced() {
    assert!(inpt::<Vec<Spaced<&str>>>("  why hello there  ")
        .unwrap()
        .into_iter()
        .map(|Spaced { inner }| inner)
        .eq(["why", "hello", "there"]));
}

#[derive(Inpt, Debug)]
#[inpt(bounds = "")]
struct Nested<'s>(InptResult<'s, Parenthetical<Box<Nested<'s>>>>, &'s str);

impl<'s> Nested<'s> {
    pub fn collect(&self) -> Vec<&'s str> {
        let mut list = if let Ok(first) = &self.0 {
            first.inner.collect()
        } else {
            Vec::new()
        };
        list.push(self.1);
        list
    }
}

#[test]
fn test_outside_parenthesis() {
    assert_eq!(inpt::<Nested>("stuff").unwrap().collect(), vec!["stuff"],);
}

#[test]
fn test_inside_parenthesis() {
    assert_eq!(inpt::<Nested>("(a)b").unwrap().collect(), vec!["a", "b"]);
}

#[test]
fn test_many_parenthesis() {
    assert_eq!(
        inpt::<Nested>("(((a)b)c)d").unwrap().collect(),
        vec!["a", "b", "c", "d"],
    );
}

#[test]
fn test_quoted_parenthesis() {
    assert_eq!(
        inpt::<Nested>("(st')\\''uff)").unwrap().collect(),
        vec!["st')\\''uff", ""],
    );
}

#[test]
fn test_whitespace_before_after_regex() {
    #[derive(Inpt, PartialEq, Debug)]
    #[inpt(regex = "then")]
    struct AThenB<'s>(#[inpt(before)] i32, #[inpt(after)] &'s str);
    assert_eq!(inpt::<AThenB>("1 then 2").unwrap(), AThenB(1, "2"));
}
