//! Argument validation and number-predicate edge cases.

use regex_range::{to_regex_range, Error, Options};

fn d() -> Options {
    Options::default()
}

#[test]
fn rejects_invalid_first_arg() {
    let err = to_regex_range("", None, &d()).unwrap_err();
    assert_eq!(err, Error::FirstArgument);
    assert!(err.to_string().contains("expected"));
}

#[test]
fn rejects_invalid_second_arg() {
    let err = to_regex_range("1", Some("abc"), &d()).unwrap_err();
    assert_eq!(err, Error::SecondArgument);
    assert!(err.to_string().contains("expected"));
}

#[test]
fn accepts_numeric_strings() {
    for v in ["5", "-5", "0", "001", "-01", "  5 ", "100020000300000"] {
        assert!(to_regex_range(v, None, &d()).is_ok(), "should accept {v:?}");
    }
}

#[test]
fn rejects_blank_and_non_numeric() {
    for v in ["", "   ", "abc", "1.5", "5e3", "0x10", "-", "+5", "1,000"] {
        assert!(
            to_regex_range(v, Some("9"), &d()).is_err(),
            "should reject max={v:?}"
        );
    }
}

#[test]
fn second_arg_checked_after_short_circuit() {
    // max equal to min by raw string short-circuits before max is validated.
    // Here max differs and is invalid, so it errors.
    assert!(to_regex_range("1", Some("{}"), &d()).is_err());
    // Single arg never validates a second.
    assert!(to_regex_range("1", None, &d()).is_ok());
}

#[test]
fn rejects_most_negative_i64() {
    // i64::MIN has no representable positive magnitude, so the pattern pipeline
    // cannot build it. It must error rather than panic.
    assert!(to_regex_range("-9223372036854775808", Some("0"), &d()).is_err());
}

#[test]
fn wide_magnitude_range_does_not_panic() {
    // The adjacency check subtracted raw i64 bounds and overflowed for ranges
    // wider than i64. It must compute the gap without overflow.
    assert!(to_regex_range("-9223372036854775807", Some("9223372036854775807"), &d()).is_ok());
}

#[test]
fn distinct_messages_for_each_argument() {
    let first = to_regex_range("x", Some("9"), &d())
        .unwrap_err()
        .to_string();
    let second = to_regex_range("1", Some("x"), &d())
        .unwrap_err()
        .to_string();
    assert_ne!(first, second);
    assert!(first.ends_with("number"));
    assert!(second.ends_with("number."));
}
