use buffer_core::{SharedMemoryReader, SharedMemoryWriter, ShmRateLimitConfig, ShmTransportConfig};
use core_types::ErrorCode;

fn test_cfg() -> ShmTransportConfig {
    let tmp = tempfile::tempdir().expect("create temp dir");
    let dir = tmp.keep();
    ShmTransportConfig {
        namespace: "robotrt-test".to_string(),
        directory: dir,
        segment_payload_bytes: 1024,
        segment_count: 4,
        rate_limit: None,
    }
}

#[test]
fn cross_process_style_reader_can_loan_writer_payload() {
    let cfg = test_cfg();
    let mut writer = SharedMemoryWriter::new(cfg.clone()).expect("create writer");
    let reader = SharedMemoryReader::new(cfg).expect("create reader");

    let data = b"hello-shm-zero-copy".to_vec();
    let reference = writer.publish(&data).expect("publish");

    let lease = reader.loan(reference).expect("loan");
    assert_eq!(lease.as_slice(), data.as_slice());
}

#[test]
fn publish_rejects_payload_larger_than_segment() {
    let cfg = test_cfg();
    let mut writer = SharedMemoryWriter::new(cfg).expect("create writer");

    let too_large = vec![1u8; 2048];
    let err = writer
        .publish(&too_large)
        .expect_err("must reject too large payload");
    assert_eq!(err.code, ErrorCode::Unsupported);
}

#[test]
fn writer_rate_limit_returns_backpressure() {
    let mut cfg = test_cfg();
    cfg.rate_limit = Some(ShmRateLimitConfig::new(128, 128));

    let mut writer = SharedMemoryWriter::new(cfg).expect("create writer");
    let first = vec![0u8; 120];
    writer.publish(&first).expect("first publish");

    let second = vec![0u8; 120];
    let err = writer
        .publish(&second)
        .expect_err("second publish should hit rate limit");
    assert_eq!(err.code, ErrorCode::Backpressure);
}

#[test]
fn stale_reference_is_detected_after_slot_reuse() {
    let mut cfg = test_cfg();
    cfg.segment_count = 1;

    let mut writer = SharedMemoryWriter::new(cfg.clone()).expect("create writer");
    let reader = SharedMemoryReader::new(cfg).expect("create reader");

    let old_ref = writer.publish(b"old-payload").expect("publish old");
    let _new_ref = writer.publish(b"new-payload").expect("publish new");

    let err = reader
        .loan(old_ref)
        .expect_err("old reference should become stale after overwrite");
    assert_eq!(err.code, ErrorCode::InvalidState);
}
