//! FC-66 — typed `CellosError::ArgvTooLarge` admission rejection.
//!
//! FC-17 (`check_argv_size_within_kernel_cmdline_limit`) caps `spec.run.argv`
//! at a 3 KiB base64-encoded budget so the Linux kernel cmdline never spills
//! its 4 KiB hard limit at boot. FC-66 promotes that rejection from a
//! string-payload `InvalidSpec` to a typed `ArgvTooLarge { encoded_bytes,
//! limit_bytes }` variant so callers can pattern-match without parsing a
//! message and so operators see the actual encoded byte count and budget.
//!
//! This integration test feeds `validate_execution_cell_document` a 5 KiB
//! argv payload and asserts the typed variant fires with sane carried fields.

use cellos_core::{
    validate_execution_cell_document, AuthorityBundle, CellosError, ExecutionCellDocument,
    ExecutionCellSpec, Lifetime, RunSpec, SecretDeliveryMode,
};

#[test]
fn validate_execution_cell_document_rejects_5kib_argv_with_typed_variant() {
    // 5 KiB of raw payload → JSON ~5 KiB → base64 ~6.7 KiB; well over the
    // 3072-byte FC-17 cap. The encoded byte count carried on the typed
    // variant must therefore be at least 5120 (the raw payload size, which
    // is itself a strict lower bound on the encoded size).
    let payload = "a".repeat(5 * 1024);

    let doc = ExecutionCellDocument {
        api_version: "cellos.io/v1".into(),
        kind: "ExecutionCell".into(),
        spec: ExecutionCellSpec {
            id: "fc66-argv-too-large".into(),
            correlation: None,
            ingress: None,
            environment: None,
            placement: None,
            policy: None,
            identity: None,
            run: Some(RunSpec {
                argv: vec!["sh".into(), payload],
                working_directory: None,
                timeout_ms: None,
                limits: None,
                secret_delivery: SecretDeliveryMode::Env,
            }),
            authority: AuthorityBundle::default(),
            lifetime: Lifetime { ttl_seconds: 1 },
            export: None,
            telemetry: None,
        },
    };

    let err = validate_execution_cell_document(&doc)
        .expect_err("5 KiB argv must be rejected at admission");

    match err {
        CellosError::ArgvTooLarge {
            encoded_bytes,
            limit_bytes,
        } => {
            assert!(
                encoded_bytes >= 5120,
                "encoded_bytes must be at least 5120 (5 KiB raw payload is a strict lower \
                 bound on the base64(json) encoded size); got {encoded_bytes}"
            );
            assert_eq!(
                limit_bytes, 3072,
                "FC-17 budget is the 3 KiB cap (3072 bytes)"
            );
            assert!(
                encoded_bytes > limit_bytes,
                "ArgvTooLarge must only fire when encoded_bytes > limit_bytes; got \
                 encoded_bytes={encoded_bytes} limit_bytes={limit_bytes}"
            );
        }
        other => panic!("expected CellosError::ArgvTooLarge, got: {other:?}"),
    }
}

/// FC-66 — verify the `Display` rendering carries the encoded byte count and
/// the static limit, so log scrapers and operator-facing surfaces have a
/// readable diagnostic out of the box.
#[test]
fn argv_too_large_display_carries_encoded_bytes_and_limit() {
    let err = CellosError::ArgvTooLarge {
        encoded_bytes: 6_842,
        limit_bytes: 3_072,
    };
    let rendered = format!("{err}");
    assert!(
        rendered.contains("6842"),
        "Display must carry the encoded byte count, got: {rendered}"
    );
    assert!(
        rendered.contains("3072"),
        "Display must carry the static limit, got: {rendered}"
    );
    assert!(
        rendered.contains("kernel cmdline"),
        "Display should mention the kernel cmdline so operators know which \
         budget tripped, got: {rendered}"
    );
}
