use super::*;
use tokio::io::{AsyncReadExt, AsyncWriteExt, duplex, sink};
use tokio::time::{Duration, timeout};

#[tokio::test]
async fn relay_to_mask_enforces_masking_session_byte_cap() {
    let initial = vec![0x16, 0x03, 0x01, 0x00, 0x01];
    let extra = vec![0xAB; 96 * 1024];

    let (client_reader, mut client_writer) = duplex(128 * 1024);
    let (mask_read, _mask_read_peer) = duplex(1024);
    let (mut mask_observer, mask_write) = duplex(256 * 1024);
    let initial_for_task = initial.clone();

    let relay = tokio::spawn(async move {
        relay_to_mask(
            client_reader,
            sink(),
            mask_read,
            mask_write,
            &initial_for_task,
            false,
            512,
            4096,
            false,
            0,
            false,
            32 * 1024,
            MASK_RELAY_IDLE_TIMEOUT,
        )
        .await;
    });

    client_writer.write_all(&extra).await.unwrap();
    client_writer.shutdown().await.unwrap();

    timeout(Duration::from_secs(2), relay)
        .await
        .unwrap()
        .unwrap();

    let mut observed = Vec::new();
    timeout(
        Duration::from_secs(2),
        mask_observer.read_to_end(&mut observed),
    )
    .await
    .unwrap()
    .unwrap();

    // In this deterministic test, relay must stop exactly at the configured cap.
    assert_eq!(
        observed.len(),
        initial.len() + (32 * 1024),
        "masked relay must forward exactly up to the cap (observed={} initial={} cap={})",
        observed.len(),
        initial.len(),
        32 * 1024
    );
}

#[tokio::test]
async fn relay_to_mask_propagates_client_half_close_without_waiting_for_other_direction_timeout() {
    let initial = b"GET /half-close HTTP/1.1\r\n".to_vec();

    let (client_reader, mut client_writer) = duplex(8 * 1024);
    let (mask_read, _mask_read_peer) = duplex(8 * 1024);
    let (mut mask_observer, mask_write) = duplex(8 * 1024);
    let initial_for_task = initial.clone();

    let relay = tokio::spawn(async move {
        relay_to_mask(
            client_reader,
            sink(),
            mask_read,
            mask_write,
            &initial_for_task,
            false,
            512,
            4096,
            false,
            0,
            false,
            32 * 1024,
            MASK_RELAY_IDLE_TIMEOUT,
        )
        .await;
    });

    client_writer.shutdown().await.unwrap();

    let mut observed = Vec::new();
    timeout(
        Duration::from_millis(80),
        mask_observer.read_to_end(&mut observed),
    )
    .await
    .expect("mask backend write side should be half-closed promptly")
    .unwrap();

    assert_eq!(&observed[..initial.len()], initial.as_slice());

    timeout(Duration::from_secs(2), relay)
        .await
        .unwrap()
        .unwrap();
}
