use crate::{
    ast::{Declaration, SyntaxTree},
    parser::Parser,
};

use super::{ParseResult, meta::Spans};

fn parse_function(s: &str) -> ParseResult<Declaration> {
    let mut spans = Spans::default();
    Parser::run_parser(Parser::root, 0, &mut spans, s)
}

fn parse(s: &str) -> ParseResult<SyntaxTree> {
    let mut spans = Spans::default();
    Parser::run_parser(Parser::tree, 0, &mut spans, s)
}

#[test]
fn function_1() {
    let s = "
        fn myfunction() {
            send-to(a,b);
        }
    ";
    parse_function(s).unwrap();
}

#[test]
fn function_2() {
    let s = "
        fn myfunction() {
            send_to(a,b);
            pph_asn.asn.set(AS200);
        }
    ";
    parse_function(s).unwrap();
}

#[test]
fn block_with_if() {
    let s = "
        fn myfunction() {
            if true { send_to(a,b); }
            pph_asn.asn.set(AS200);
        }
    ";
    parse_function(s).unwrap();
}

#[test]
fn block_with_if_with_semicolon() {
    let s = "
        fn myfunction() {
            if true { send_to(a,b); };
            pph_asn.asn.set(AS200);
        }
    ";
    parse_function(s).unwrap();
}

#[test]
fn top_level_import() {
    let s = "
        import foo.bar;

        fn myfunction() {
            1 + 1;
        }
    ";
    parse(s).unwrap();
}

#[test]
fn block_import_1() {
    let s = "
        fn myfunction() {
            import foo.bar;
            1 + 1;
        }
    ";
    parse(s).unwrap();
}

#[test]
fn block_import_2() {
    let s = "
        fn myfunction() {
            1 + 1;
            import foo.bar;
        }
    ";
    parse(s).unwrap();
}

#[test]
fn list_import() {
    let s = "
        fn myfunction() {
            import foo.{bar1, bar2};
            1 + 1;
        }
    ";

    parse(s).unwrap();
}

#[test]
fn nested_list_import() {
    let s = "
        fn myfunction() {
            import foo.{baz.{fn1, fn2, fn3}, baz.{bar1, bar2}};
            1 + 1;
        }
    ";

    parse(s).unwrap();
}

#[test]
fn sublists_only_import() {
    let s = "
        fn myfunction() {
            import foo.{{fn1, fn2, fn3}, {bar1, bar2}};
            1 + 1;
        }
    ";

    parse(s).unwrap();
}

#[test]
fn sublist_sublist_import() {
    let s = "
        fn myfunction() {
            import foo.{item1.{fn1, fn2}, item2.{item3.fn3, item4.{fn5, fn6}}};
            1 + 1;
        }
    ";

    parse(s).unwrap();
}

#[test]
fn variant_empty() {
    let s = "
        variant Foo {}
    ";
    parse(s).unwrap();
}

#[test]
fn variant_single() {
    let s = "
        variant Foo { Bar }
    ";
    parse(s).unwrap();
}

#[test]
fn variant_single_comma() {
    let s = "
        variant Foo { Bar, }
    ";
    parse(s).unwrap();
}

#[test]
fn variant_single_field() {
    let s = "
        variant Foo { Bar(i32) }
    ";
    parse(s).unwrap();
}

#[test]
fn variant_single_field_comma() {
    let s = "
        variant Foo { Bar(i32,) }
    ";
    parse(s).unwrap();
}

#[test]
fn variant_single_field_comma_comma() {
    let s = "
        variant Foo { Bar(i32,), }
    ";
    parse(s).unwrap();
}

#[test]
fn variant_two_fields() {
    let s = "
        variant Foo { Bar(i32, u32) }
    ";
    parse(s).unwrap();
}

#[test]
fn variant_multiple_variants() {
    let s = "
        variant Foo {
            U(u32),
            I(i32),
        }
    ";
    parse(s).unwrap();
}

#[test]
fn variant_redundant_square_brackets() {
    let s = "
        variant Foo[] {
            U(u32[]),
            I(i32[]),
        }
    ";
    parse(s).unwrap();
}
