use earl::expression::parser::parse_expression;

#[test]
fn parses_valid_expression_with_nested_values() {
    let expr = parse_expression(
        "github.search_issues(\"hello\", flag=true, meta={\"k\":1}, arr=[1,2], count=10)",
    )
    .unwrap();
    assert_eq!(expr.provider, "github");
    assert_eq!(expr.command, "search_issues");
    assert_eq!(expr.positional_args.len(), 1);
    assert_eq!(expr.named_args.len(), 4);
}

#[test]
fn fails_on_duplicate_named_argument() {
    let err = parse_expression("x.y(a=1, a=2)").unwrap_err();
    assert!(err.to_string().contains("duplicate named argument `a`"));
}

#[test]
fn fails_on_positional_after_named() {
    let err = parse_expression("x.y(a=1, 2)").unwrap_err();
    assert!(
        err.to_string()
            .contains("positional argument cannot appear after named argument")
    );
}

#[test]
fn fails_on_invalid_token_and_trailing_garbage() {
    let err = parse_expression("x.y(@)").unwrap_err();
    assert!(err.to_string().contains("invalid token"));

    let err = parse_expression("x.y() trailing").unwrap_err();
    assert!(err.to_string().contains("invalid token"));
}

#[test]
fn fails_on_malformed_array_and_object() {
    let err = parse_expression("x.y([1,2)").unwrap_err();
    assert!(err.to_string().contains("expected") || err.to_string().contains("unexpected end"));

    let err = parse_expression("x.y({\"k\" 1})").unwrap_err();
    assert!(err.to_string().contains("expected `:`"));
}

#[test]
fn fails_on_invalid_number() {
    let err = parse_expression("x.y(1e)").unwrap_err();
    assert!(err.to_string().contains("invalid number `1e`"));
}

#[test]
fn fails_on_unterminated_string() {
    let err = parse_expression("x.y(\"hello)").unwrap_err();
    assert!(err.to_string().contains("unexpected end of input"));
}
