use super::*;

#[test]
fn rejects_unowned_owner_for_reviewed_entries() {
    let err = parse_err(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "allow-unowned-reviewed"
                kind = "panic"
                path = "src/lib.rs"
                owner = "unowned"
                classification = "reviewed"
                reason = "fixture"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    );

    assert!(err.contains("allow-unowned-reviewed missing concrete owner"));
}

#[test]
fn rejects_owner_with_surrounding_whitespace() {
    let err = parse_err(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "padded-owner"
                kind = "panic"
                path = "src/lib.rs"
                owner = " core "
                classification = "reviewed"
                reason = "fixture"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    );

    assert!(err.contains("padded-owner owner must not have leading or trailing whitespace"));
}

#[test]
fn rejects_classification_with_surrounding_whitespace() {
    let err = parse_err(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "padded-classification"
                kind = "panic"
                path = "src/lib.rs"
                owner = "core"
                classification = " baseline_debt "
                reason = "fixture"
                created = "2026-05-26"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    );

    assert!(err.contains(
        "padded-classification classification must not have leading or trailing whitespace"
    ));
}

#[test]
fn rejects_reason_with_surrounding_whitespace() {
    let err = parse_err(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "padded-reason"
                kind = "panic"
                path = "src/lib.rs"
                owner = "core"
                classification = "reviewed"
                reason = " fixture "
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    );

    assert!(err.contains("padded-reason reason must not have leading or trailing whitespace"));
}

#[test]
fn allows_unowned_owner_for_baseline_debt() {
    let cfg = parse_policy(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "allow-unowned-baseline"
                kind = "panic"
                path = "src/lib.rs"
                owner = "unowned"
                classification = "baseline_debt"
                reason = "Generated by cargo-allow propose; requires human review."
                created = "2026-05-26"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    )
    .unwrap_or_else(|err| std::panic::panic_any(format!("policy should parse: {err}")));

    let Some(entry) = cfg.allow.first() else {
        std::panic::panic_any("policy should contain fixture allow entry");
    };
    assert_eq!(entry.owner, "unowned");
}

#[test]
fn rejects_duplicate_ids() {
    let err = parse_policy(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "x"
                kind = "non_rust_file"
                path = "a.py"
                owner = "o"
                classification = "c"
                reason = "r"
                expires = "2026-08-01"
                [allow.selector]
                glob = "a.py"
                [[allow]]
                id = "x"
                kind = "non_rust_file"
                path = "b.py"
                owner = "o"
                classification = "c"
                reason = "r"
                expires = "2026-08-01"
                [allow.selector]
                glob = "b.py"
            "#,
    )
    .unwrap_err();
    assert!(err.to_string().contains("duplicate"));
}

#[test]
fn accepts_allow_id_token_characters() {
    let cfg = parse_policy(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "allow_test-1"
                kind = "panic"
                path = "src/lib.rs"
                owner = "core"
                classification = "test"
                reason = "fixture"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    )
    .unwrap_or_else(|err| std::panic::panic_any(format!("policy should parse: {err}")));

    assert_eq!(cfg.allow[0].id, "allow_test-1");
}

#[test]
fn rejects_allow_id_with_surrounding_whitespace() {
    let err = parse_err(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = " allow-1 "
                kind = "panic"
                path = "src/lib.rs"
                owner = "core"
                classification = "test"
                reason = "fixture"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    );

    assert!(err.contains("allow id ` allow-1 ` must not have leading or trailing whitespace"));
}

#[test]
fn rejects_allow_id_with_unsupported_characters() {
    let err = parse_err(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "allow:1"
                kind = "panic"
                path = "src/lib.rs"
                owner = "core"
                classification = "test"
                reason = "fixture"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    );

    assert!(err.contains(
        "allow id `allow:1` may contain only ASCII letters, digits, hyphen, or underscore"
    ));
}

#[test]
fn rejects_blank_allow_family() {
    let err = parse_err(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "blank-family"
                kind = "panic"
                family = "   "
                path = "src/lib.rs"
                owner = "core"
                classification = "test"
                reason = "fixture"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    );

    assert!(err.contains("blank-family family must not be empty"));
}

#[test]
fn rejects_family_with_surrounding_whitespace() {
    let err = parse_err(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "padded-family"
                kind = "panic"
                family = " unwrap "
                path = "src/lib.rs"
                owner = "core"
                classification = "test"
                reason = "fixture"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    );

    assert!(err.contains("padded-family family must not have leading or trailing whitespace"));
}

#[test]
fn rejects_zero_occurrence_limit() {
    let err = parse_err(
        r#"
                policy = "cargo-allow"
                [[allow]]
                id = "allow-zero"
                kind = "panic"
                path = "src/lib.rs"
                owner = "core"
                classification = "baseline_debt"
                reason = "Generated baseline debt."
                occurrence_limit = 0
                created = "2026-05-26"
                expires = "2026-08-01"
                [allow.selector]
                ast_kind = "method_call"
                callee = "unwrap"
            "#,
    );

    assert!(
        err.to_string()
            .contains("occurrence_limit must be greater than zero")
    );
}
