use super::*;

#[test]
fn builder_ephemeral_succeeds() {
    let db = TidalDb::builder().ephemeral().open();
    assert!(db.is_ok());
}

#[test]
fn builder_default_is_ephemeral() {
    let db = TidalDb::builder().open();
    assert!(db.is_ok());
}

#[test]
fn builder_persistent_requires_data_dir() {
    // Construct a persistent-mode builder without calling with_data_dir
    // by manually setting mode.
    let builder = TidalDbBuilder {
        config: Config {
            mode: StorageMode::Persistent,
            data_dir: None,
            wal_dir: None,
            cache_dir: None,
            cluster: Default::default(),
        },
        metrics_addr: None,
        schema: None,
        rate_limiter_config: None,
        transport: None,
    };
    let result = builder.validate();
    assert!(result.is_err());
    let err = result.expect_err("should fail");
    assert!(
        matches!(err, ConfigError::MissingDataDir),
        "expected MissingDataDir, got: {err}"
    );
}

#[test]
fn builder_persistent_missing_dir() {
    let result = TidalDb::builder()
        .with_data_dir("/nonexistent/path/that/does/not/exist")
        .open();
    assert!(result.is_err());
    let err_msg = result.expect_err("should fail").to_string();
    assert!(
        err_msg.contains("does not exist"),
        "expected DirectoryNotFound, got: {err_msg}"
    );
}

#[test]
fn builder_persistent_existing_dir() {
    let tmp = tempfile::tempdir().expect("failed to create tempdir");
    let result = TidalDb::builder().with_data_dir(tmp.path()).open();
    assert!(result.is_ok(), "open with valid tempdir should succeed");
}

#[test]
fn health_check_ok() {
    let db = TidalDb::builder().ephemeral().open().expect("open failed");
    assert!(db.health_check().is_ok());
}

#[test]
fn close_ok() {
    let db = TidalDb::builder().ephemeral().open().expect("open failed");
    assert!(db.close().is_ok());
}

#[test]
fn builder_with_wal_and_cache_dir() {
    let tmp = tempfile::tempdir().expect("failed to create tempdir");
    let wal = tmp.path().join("wal");
    let cache = tmp.path().join("cache");
    std::fs::create_dir_all(&wal).expect("mkdir wal");
    std::fs::create_dir_all(&cache).expect("mkdir cache");

    let result = TidalDb::builder()
        .with_data_dir(tmp.path())
        .wal_dir(&wal)
        .cache_dir(&cache)
        .open();
    assert!(
        result.is_ok(),
        "open with explicit wal/cache dirs should succeed"
    );
}

#[test]
fn builder_ephemeral_resets_dirs() {
    let builder = TidalDb::builder()
        .with_data_dir("/some/path")
        .wal_dir("/some/wal")
        .cache_dir("/some/cache")
        .ephemeral();

    assert_eq!(builder.config.mode, StorageMode::Ephemeral);
    assert!(builder.config.data_dir.is_none());
    assert!(builder.config.wal_dir.is_none());
    assert!(builder.config.cache_dir.is_none());
}

#[test]
fn builder_wal_dir_nonexistent() {
    let tmp = tempfile::tempdir().expect("failed to create tempdir");
    let result = TidalDb::builder()
        .with_data_dir(tmp.path())
        .wal_dir("/nonexistent/wal")
        .open();
    assert!(result.is_err());
    let err_msg = result.expect_err("should fail").to_string();
    assert!(err_msg.contains("does not exist"));
}

#[test]
fn resolve_defaults_sets_wal_and_cache() {
    let tmp = tempfile::tempdir().expect("failed to create tempdir");
    let mut builder = TidalDb::builder().with_data_dir(tmp.path());
    assert!(builder.config.wal_dir.is_none());
    assert!(builder.config.cache_dir.is_none());

    builder.resolve_defaults();

    let paths = Paths::new(tmp.path());
    assert_eq!(builder.config.wal_dir.as_ref(), Some(&paths.wal_dir()));
    assert_eq!(builder.config.cache_dir.as_ref(), Some(&paths.cache_dir()));
}

#[test]
fn resolve_defaults_preserves_explicit_overrides() {
    let tmp = tempfile::tempdir().expect("failed to create tempdir");
    let custom_wal = tmp.path().join("custom_wal");
    let custom_cache = tmp.path().join("custom_cache");

    let mut builder = TidalDb::builder()
        .with_data_dir(tmp.path())
        .wal_dir(&custom_wal)
        .cache_dir(&custom_cache);

    builder.resolve_defaults();

    assert_eq!(builder.config.wal_dir.as_ref(), Some(&custom_wal));
    assert_eq!(builder.config.cache_dir.as_ref(), Some(&custom_cache));
}

#[test]
fn resolve_defaults_noop_for_ephemeral() {
    let mut builder = TidalDb::builder().ephemeral();
    builder.resolve_defaults();

    assert!(builder.config.wal_dir.is_none());
    assert!(builder.config.cache_dir.is_none());
}

// ── Fix A: Directory lock tests ─────────────────────────────────────

#[test]
fn dual_open_same_directory_fails() {
    let dir = tempfile::tempdir().expect("tempdir");
    // First open succeeds (no schema -- M0 mode, but still persistent).
    let _db1 = TidalDb::builder()
        .with_data_dir(dir.path().to_path_buf())
        .open()
        .expect("first open should succeed");

    // Second open on the same directory must fail with DataDirLocked.
    let result = TidalDb::builder()
        .with_data_dir(dir.path().to_path_buf())
        .open();
    assert!(result.is_err(), "expected error for dual open");
    let err_msg = result.expect_err("should fail").to_string();
    assert!(
        err_msg.contains("already open"),
        "expected DataDirLocked, got: {err_msg}"
    );
}

#[test]
fn lock_released_after_close() {
    let dir = tempfile::tempdir().expect("tempdir");
    {
        let db = TidalDb::builder()
            .with_data_dir(dir.path().to_path_buf())
            .open()
            .expect("open");
        db.close().expect("close");
    }
    // After close (and drop), the lock should be released.
    let db2 = TidalDb::builder()
        .with_data_dir(dir.path().to_path_buf())
        .open();
    assert!(
        db2.is_ok(),
        "second open after close should succeed: {:?}",
        db2.err()
    );
}

#[test]
fn ephemeral_mode_skips_lock() {
    // Two ephemeral databases should both succeed (no lock file).
    let _db1 = TidalDb::builder().ephemeral().open().expect("open 1");
    let _db2 = TidalDb::builder().ephemeral().open().expect("open 2");
}
