mod common;

use std::sync::{
    atomic::{AtomicBool, Ordering},
    Arc,
};

#[test]
fn ditto_shutdown() {
    let data_dir = tempfile::tempdir().unwrap();
    let data_dir_path = data_dir.path();
    let ditto = common::get_online_ditto_with_persistent_dir(data_dir_path).unwrap();

    ditto.start_sync().unwrap();
    ditto.stop_sync();
    drop(ditto);

    let ditto_2 = common::get_online_ditto_with_persistent_dir(data_dir_path).unwrap();
    drop(ditto_2);
}

#[test]
fn ensure_activated_before_starting_sync() {
    let ditto = common::get_inactive_ditto().unwrap();
    dbg!(ditto.is_activated());
    let res = ditto.start_sync();
    assert!(res.is_err());
    let err = res.err().unwrap();
    assert_eq!(err.to_string(), "Sync could not be started because Ditto has not yet been activated. This can be achieved with a successful call to `set_license_token`. If you need to obtain a license token then please visit https://portal.ditto.live.");
}

#[test]
fn ensure_online_is_activated_before_starting_sync() {
    let ditto = common::get_online_ditto().unwrap();
    assert!(ditto.is_activated());
    // We go through this extra `Result`-wrapping closure layer to get
    // the corresponding API doc Rust snippet to feature a more idiomatic `?`
    let res = (|| {
        //@ditto/snippet-start sync-basic
        ditto.start_sync()?;
        //@ditto/snippet-end
        Ok::<(), ::dittolive_ditto::error::DittoError>(())
    })();
    assert!(res.is_ok());
}

/// A basic smoke test which tests that the FFI bindings are wired up
/// correctly and nothing horrible happens.
#[test]
fn test_garbage_collection() {
    let ditto = common::get_ditto().unwrap();
    ditto.run_garbage_collection();
}

/// Test that setting a device name is working correctly
#[test]
fn test_set_device_name() {
    let ditto = common::get_ditto().unwrap();
    ditto.set_device_name("my_custom_device_name");

    let finished = Arc::new(AtomicBool::new(false));
    let finished_1 = Arc::clone(&finished);

    let _presence_observer = ditto.presence().observe(move |presence| {
        let local_peer = &presence.local_peer;

        assert_eq!(&local_peer.device_name, "my_custom_device_name");
        finished_1.store(true, Ordering::SeqCst);
    });

    while !finished.load(Ordering::SeqCst) {
        std::thread::yield_now();
    }
}

/// Test that monitoring disk usage works
#[test]
fn test_observe_disk_usage() {
    let ditto = common::get_ditto().unwrap();

    let finished = Arc::new(AtomicBool::new(false));
    let finished_1 = Arc::clone(&finished);

    let _observer = ditto.disk_usage().observe(move |_disk_usage_tree| {
        finished_1.store(true, Ordering::SeqCst);
    });
    let mut data_path = std::path::PathBuf::from(ditto.persistence_directory());
    data_path.push("random_file_name");
    std::fs::File::create(data_path).unwrap();

    while !finished.load(Ordering::SeqCst) {
        std::thread::yield_now();
    }
}
