//! Integration tests for the sandboxed storage layout.
//!
//! Validates that [`Paths`] and [`TempTidalHome`] provide correct,
//! isolated filesystem sandboxes for tidalDB instances.

use tidaldb::TidalDb;
use tidaldb::db::temp::TempTidalHome;

// =============================================================================
// TempTidalHome isolation
// =============================================================================

#[test]
fn two_temp_homes_have_non_overlapping_paths() {
    let home1 = TempTidalHome::new().unwrap();
    let home2 = TempTidalHome::new().unwrap();

    assert_ne!(
        home1.path(),
        home2.path(),
        "two TempTidalHome instances must have different base paths"
    );

    // Verify neither is a prefix of the other (true isolation).
    assert!(
        !home1.path().starts_with(home2.path()),
        "home1 should not be a subdirectory of home2"
    );
    assert!(
        !home2.path().starts_with(home1.path()),
        "home2 should not be a subdirectory of home1"
    );
}

// =============================================================================
// Drop removes directory
// =============================================================================

#[test]
fn drop_removes_directory_with_contents() {
    let path = {
        let home = TempTidalHome::new().unwrap();
        let p = home.path().to_owned();

        // Create a file inside so the directory is non-empty.
        std::fs::write(p.join("sentinel.txt"), b"test data").unwrap();
        assert!(p.exists(), "directory should exist before drop");
        p
        // home dropped here
    };
    assert!(!path.exists(), "directory should be removed after drop");
}

// =============================================================================
// with_preserve keeps directory
// =============================================================================

#[test]
fn with_preserve_keeps_directory_after_drop() {
    let path = {
        let home = TempTidalHome::with_preserve().unwrap();
        let p = home.path().to_owned();

        std::fs::write(p.join("sentinel.txt"), b"test data").unwrap();
        p
        // home dropped here, but preserve=true
    };
    assert!(
        path.exists(),
        "directory should still exist after drop with preserve"
    );

    // Manual cleanup.
    std::fs::remove_dir_all(&path).unwrap();
}

// =============================================================================
// Paths::ensure_all creates expected subdirectories
// =============================================================================

#[test]
fn ensure_all_creates_all_subdirectories() {
    let home = TempTidalHome::new().unwrap();
    let paths = home.paths();

    // Before ensure_all, subdirectories should not exist.
    assert!(!paths.wal_dir().exists());
    assert!(!paths.items_dir().exists());
    assert!(!paths.users_dir().exists());
    assert!(!paths.creators_dir().exists());
    assert!(!paths.cache_dir().exists());

    paths.ensure_all().unwrap();

    // After ensure_all, all subdirectories should exist.
    assert!(paths.wal_dir().is_dir(), "wal dir should exist");
    assert!(paths.items_dir().is_dir(), "items dir should exist");
    assert!(paths.users_dir().is_dir(), "users dir should exist");
    assert!(paths.creators_dir().is_dir(), "creators dir should exist");
    assert!(paths.cache_dir().is_dir(), "cache dir should exist");
}

// =============================================================================
// Two builders with different TempTidalHome roots never collide
// =============================================================================

#[test]
fn two_builders_with_different_homes_are_isolated() {
    let home1 = TempTidalHome::new().unwrap();
    let home2 = TempTidalHome::new().unwrap();

    let paths1 = home1.paths();
    let paths2 = home2.paths();

    paths1.ensure_all().unwrap();
    paths2.ensure_all().unwrap();

    // Write a file into home1's wal directory.
    let sentinel1 = paths1.wal_dir().join("segment-001");
    std::fs::write(&sentinel1, b"home1 wal data").unwrap();

    // Write a file into home2's wal directory.
    let sentinel2 = paths2.wal_dir().join("segment-001");
    std::fs::write(&sentinel2, b"home2 wal data").unwrap();

    // Verify each sees only its own data.
    let data1 = std::fs::read(&sentinel1).unwrap();
    let data2 = std::fs::read(&sentinel2).unwrap();

    assert_eq!(data1, b"home1 wal data");
    assert_eq!(data2, b"home2 wal data");

    // Verify the other home's directory does not contain the wrong data.
    assert_ne!(data1, data2);
}

// =============================================================================
// Builder integrates with Paths via TempTidalHome
// =============================================================================

#[test]
fn builder_with_temp_home_opens_successfully() {
    let home = TempTidalHome::new().unwrap();

    // The builder validates data_dir exists (TempTidalHome creates it).
    // Resolved defaults (wal_dir, cache_dir) are populated after validation
    // so they don't need to pre-exist.
    let db = TidalDb::builder().with_data_dir(home.path()).open();
    assert!(db.is_ok(), "builder with TempTidalHome should succeed");
}

#[test]
fn ensure_all_is_idempotent() {
    let home = TempTidalHome::new().unwrap();
    let paths = home.paths();

    paths.ensure_all().unwrap();

    // Write a file to verify it survives a second ensure_all.
    std::fs::write(paths.wal_dir().join("segment-001"), b"data").unwrap();

    paths.ensure_all().unwrap();

    // File should still exist.
    assert!(paths.wal_dir().join("segment-001").exists());
}

#[test]
fn paths_base_matches_temp_home_path() {
    let home = TempTidalHome::new().unwrap();
    let paths = home.paths();
    assert_eq!(paths.base(), home.path());
}
