// Simulated client-to-server HID write integration.
//
// Scope: pump keyboard and mouse reports into fake HID endpoint files.
// Targets: `server/src/runtime_support/hid_write.rs` plus shared report
// payload contracts.
// Why: we need confidence that the server-side HID write path preserves report
// bytes and ordering before any real gadget or uinput device is involved.

use std::sync::Arc;

use lesavka_server::runtime_support::write_hid_report;
use tokio::sync::Mutex;

async fn close_fake_hid(handle: &Arc<Mutex<Option<tokio::fs::File>>>) {
    let mut guard = handle.lock().await;
    if let Some(file) = guard.as_mut() {
        file.sync_all().await.expect("sync fake HID endpoint");
    }
    drop(guard.take());
}

async fn write_reports(path: &std::path::Path, reports: &[[u8; 8]]) {
    std::fs::File::create(path).expect("create fake HID endpoint");
    let handle = Arc::new(Mutex::new(None));
    let path = path.to_string_lossy().to_string();

    for report in reports {
        write_hid_report(&handle, &path, report)
            .await
            .expect("write fake HID report");
    }

    close_fake_hid(&handle).await;
}

#[tokio::test]
async fn keyboard_reports_reach_fake_hid_writer_in_order() {
    let dir = tempfile::tempdir().expect("tempdir");
    let endpoint = dir.path().join("hidg0");
    let reports = [
        [0x02, 0, 0, 0, 0, 0, 0, 0],
        [0x02, 0, 0x04, 0, 0, 0, 0, 0],
        [0x02, 0, 0, 0, 0, 0, 0, 0],
        [0; 8],
    ];

    write_reports(&endpoint, &reports).await;

    let bytes = std::fs::read(endpoint).expect("read fake HID endpoint");
    assert_eq!(bytes, reports.concat());
}

#[tokio::test]
async fn keyboard_and_mouse_writers_do_not_cross_contaminate_endpoint_bytes() {
    let dir = tempfile::tempdir().expect("tempdir");
    let keyboard_endpoint = dir.path().join("hidg0");
    let mouse_endpoint = dir.path().join("hidg1");
    let keyboard_handle = Arc::new(Mutex::new(None));
    let mouse_handle = Arc::new(Mutex::new(None));
    std::fs::File::create(&keyboard_endpoint).expect("create keyboard endpoint");
    std::fs::File::create(&mouse_endpoint).expect("create mouse endpoint");
    let keyboard_path = keyboard_endpoint.to_string_lossy().to_string();
    let mouse_path = mouse_endpoint.to_string_lossy().to_string();

    write_hid_report(
        &keyboard_handle,
        &keyboard_path,
        &[0, 0, 0x04, 0, 0, 0, 0, 0],
    )
    .await
    .expect("write keyboard endpoint");
    let mouse_report = [0x01, 4, 252, 0];
    write_hid_report(&mouse_handle, &mouse_path, &mouse_report)
        .await
        .expect("write mouse endpoint");
    close_fake_hid(&keyboard_handle).await;
    close_fake_hid(&mouse_handle).await;

    assert_eq!(
        std::fs::read(keyboard_endpoint).expect("read keyboard endpoint"),
        vec![0, 0, 0x04, 0, 0, 0, 0, 0]
    );
    assert_eq!(
        std::fs::read(mouse_endpoint).expect("read mouse endpoint"),
        vec![0x01, 4, 252, 0]
    );
}
