use std::fs;

use rpki::fetch::rsync::RsyncFetcher;
use rpki::fetch::rsync_system::{SystemRsyncConfig, SystemRsyncFetcher};

#[test]
fn system_rsync_fetcher_can_sync_from_local_directory_for_tests() {
    let tmp = tempfile::tempdir().expect("tempdir");
    let src = tmp.path().join("src");
    let nested = src.join("sub");
    fs::create_dir_all(&nested).expect("mkdir");
    fs::write(src.join("a.txt"), b"aaa").expect("write a");
    fs::write(nested.join("b.txt"), b"bbb").expect("write b");

    let config = SystemRsyncConfig {
        rsync_bin: "rsync".into(),
        ..Default::default()
    };
    let fetcher = SystemRsyncFetcher::new(config);

    let base = src.to_string_lossy().to_string();
    let out = fetcher.fetch_objects(&base).expect("fetch objects");

    let mut saw_a = false;
    let mut saw_b = false;
    for (uri, bytes) in out {
        if uri.ends_with("a.txt") {
            assert_eq!(bytes, b"aaa");
            saw_a = true;
        }
        if uri.ends_with("sub/b.txt") {
            assert_eq!(bytes, b"bbb");
            saw_b = true;
        }
    }
    assert!(saw_a, "expected a.txt");
    assert!(saw_b, "expected sub/b.txt");
}

#[test]
fn system_rsync_fetcher_can_reuse_persistent_mirror_directory() {
    let tmp = tempfile::tempdir().expect("tempdir");
    let src = tmp.path().join("src");
    let nested = src.join("sub");
    fs::create_dir_all(&nested).expect("mkdir");
    fs::write(src.join("a.txt"), b"aaa").expect("write a");
    fs::write(nested.join("b.txt"), b"bbb").expect("write b");

    let mirror_root = tmp.path().join("mirror");
    let config = SystemRsyncConfig {
        rsync_bin: "rsync".into(),
        mirror_root: Some(mirror_root.clone()),
        ..Default::default()
    };
    let fetcher = SystemRsyncFetcher::new(config);

    let base = src.to_string_lossy().to_string();

    // First sync creates the mirror directory.
    let out1 = fetcher.fetch_objects(&base).expect("fetch objects #1");
    assert!(out1.iter().any(|(u, _)| u.ends_with("a.txt")));
    assert!(out1.iter().any(|(u, _)| u.ends_with("sub/b.txt")));

    let dirs1: Vec<_> = std::fs::read_dir(&mirror_root)
        .expect("read mirror root")
        .filter_map(|e| e.ok())
        .filter(|e| e.path().is_dir())
        .collect();
    assert_eq!(dirs1.len(), 1, "expected exactly one mirror directory");

    // Second sync should reuse the same mirror directory (stable hash mapping).
    let out2 = fetcher.fetch_objects(&base).expect("fetch objects #2");
    assert!(out2.iter().any(|(u, _)| u.ends_with("a.txt")));
    assert!(out2.iter().any(|(u, _)| u.ends_with("sub/b.txt")));

    let dirs2: Vec<_> = std::fs::read_dir(&mirror_root)
        .expect("read mirror root")
        .filter_map(|e| e.ok())
        .filter(|e| e.path().is_dir())
        .collect();
    assert_eq!(dirs2.len(), 1, "expected mirror directory to be reused");
}
