//! Integration tests for public ioutil functions.
//!
//! pub(crate) functions (safe_resolve, read_to_string, entry_metadata, list_dirs,
//! move_to_trash, disk_usage) are covered by internal unit tests in src/ioutil.rs.

use std::path::Path;

#[test]
fn test_os_to_string() {
    let os = std::ffi::OsString::from("hello.txt");
    assert_eq!(mad_hatter::ioutil::os_to_string(os), "hello.txt");
}

#[test]
fn test_file_name_string_normal() {
    let path = Path::new("/tmp/foo/bar.txt");
    assert_eq!(mad_hatter::ioutil::file_name_string(path), "bar.txt");
}

#[test]
fn test_file_name_string_no_name() {
    let path = Path::new("/");
    assert_eq!(mad_hatter::ioutil::file_name_string(path), "");
}

#[test]
fn test_file_name_string_relative() {
    let path = Path::new("docs/readme.md");
    assert_eq!(mad_hatter::ioutil::file_name_string(path), "readme.md");
}

#[test]
fn test_path_to_string() {
    let path = Path::new("/tmp/foo/bar");
    assert_eq!(mad_hatter::ioutil::path_to_string(path), "/tmp/foo/bar");
}

#[test]
fn test_current_dir_path_returns_dot() {
    // current_dir_path is documented as equivalent to PathBuf::from(".")
    let cwd = mad_hatter::ioutil::current_dir_path();
    assert_eq!(cwd, std::path::PathBuf::from("."));
    // "." resolves to actual cwd; should exist
    assert!(cwd.exists(), "'.' should exist as relative cwd: {:?}", cwd);
}

#[test]
fn test_kb_to_bytes() {
    assert_eq!(mad_hatter::ioutil::kb_to_bytes(0), 0);
    assert_eq!(mad_hatter::ioutil::kb_to_bytes(1), 1024);
    assert_eq!(mad_hatter::ioutil::kb_to_bytes(1024), 1024 * 1024);
}

#[test]
fn test_bytes_to_kb() {
    assert_eq!(mad_hatter::ioutil::bytes_to_kb(0), 0);
    assert_eq!(mad_hatter::ioutil::bytes_to_kb(1024), 1);
    assert_eq!(mad_hatter::ioutil::bytes_to_kb(2048), 2);
    // Floor division
    assert_eq!(mad_hatter::ioutil::bytes_to_kb(1023), 0);
    assert_eq!(mad_hatter::ioutil::bytes_to_kb(1500), 1);
}

#[test]
fn test_mb_to_bytes() {
    assert_eq!(mad_hatter::ioutil::mb_to_bytes(0), 0);
    assert_eq!(mad_hatter::ioutil::mb_to_bytes(1), 1024 * 1024);
    assert_eq!(mad_hatter::ioutil::mb_to_bytes(16), 16 * 1024 * 1024);
}

#[test]
fn test_kb_mb_roundtrip() {
    // 4 MB = 4096 KB = 4 * 1024 * 1024 bytes
    let bytes = mad_hatter::ioutil::mb_to_bytes(4);
    assert_eq!(mad_hatter::ioutil::bytes_to_kb(bytes), 4096);
}

#[test]
fn test_exponential_backoff_zero_count() {
    // count=0 returns 0 (no backoff)
    assert_eq!(mad_hatter::ioutil::exponential_backoff(0, 2, 5, 30), 0);
}

#[test]
fn test_exponential_backoff_first_attempt() {
    // count=1: base * 2^0 = base * 1
    assert_eq!(mad_hatter::ioutil::exponential_backoff(1, 2, 5, 30), 2);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(1, 5, 5, 30), 5);
}

#[test]
fn test_exponential_backoff_growth() {
    // base=2, max_exp=5, cap=30
    // count=1 → 2 * 2^0 = 2
    // count=2 → 2 * 2^1 = 4
    // count=3 → 2 * 2^2 = 8
    // count=4 → 2 * 2^3 = 16
    // count=5 → 2 * 2^4 = 32 → capped to 30
    // count=6 → 2 * 2^5 = 64 → capped to 30 (and max_exp saturates at 5)
    assert_eq!(mad_hatter::ioutil::exponential_backoff(1, 2, 5, 30), 2);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(2, 2, 5, 30), 4);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(3, 2, 5, 30), 8);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(4, 2, 5, 30), 16);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(5, 2, 5, 30), 30);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(6, 2, 5, 30), 30);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(100, 2, 5, 30), 30);
}

#[test]
fn test_exponential_backoff_max_exp_clamps() {
    // max_exp=3 means exponent clamps at 3
    // count=4 → base * 2^3 = base * 8
    // count=5 → same (exp saturated)
    assert_eq!(mad_hatter::ioutil::exponential_backoff(4, 1, 3, 1000), 8);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(5, 1, 3, 1000), 8);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(10, 1, 3, 1000), 8);
}

#[test]
fn test_exponential_backoff_cap_limits() {
    // Even without max_exp saturation, cap is the hard ceiling
    assert_eq!(mad_hatter::ioutil::exponential_backoff(3, 100, 10, 500), 400);
    assert_eq!(mad_hatter::ioutil::exponential_backoff(4, 100, 10, 500), 500);
}