use std::fs;
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_safe_resolve_normal() {
    let dir = tempfile::tempdir().unwrap();
    let sub = dir.path().join("sub");
    fs::create_dir(&sub).unwrap();
    fs::write(sub.join("file.txt"), "hello").unwrap();

    let resolved = mad_hatter::ioutil::safe_resolve(dir.path(), "sub/file.txt").unwrap();
    assert!(resolved.ends_with("sub/file.txt"));
    assert!(resolved.is_file());
}

#[test]
fn test_safe_resolve_empty_returns_base() {
    let dir = tempfile::tempdir().unwrap();
    let resolved = mad_hatter::ioutil::safe_resolve(dir.path(), "").unwrap();
    assert_eq!(resolved, dir.path().canonicalize().unwrap());
}

#[test]
fn test_safe_resolve_traversal_denied() {
    let dir = tempfile::tempdir().unwrap();
    // Create a file outside the base
    let result = mad_hatter::ioutil::safe_resolve(dir.path(), "../../etc/passwd");
    // This may fail with NotFound (canonicalize fails) or PermissionDenied (traversal check)
    assert!(result.is_err());
}

#[test]
fn test_safe_resolve_nonexistent() {
    let dir = tempfile::tempdir().unwrap();
    let result = mad_hatter::ioutil::safe_resolve(dir.path(), "nonexistent.txt");
    assert!(result.is_err()); // canonicalize fails for nonexistent path
}

#[test]
fn test_read_to_string_success() {
    let dir = tempfile::tempdir().unwrap();
    let file = dir.path().join("test.txt");
    fs::write(&file, "hello world").unwrap();

    let content = mad_hatter::ioutil::read_to_string(&file).unwrap();
    assert_eq!(content, "hello world");
}

#[test]
fn test_read_to_string_error_includes_path() {
    let result = mad_hatter::ioutil::read_to_string("/nonexistent/path/file.txt");
    assert!(result.is_err());
    let err = result.unwrap_err();
    assert!(
        err.to_string().contains("/nonexistent/path/file.txt"),
        "Error should include path: {}",
        err
    );
}

#[test]
fn test_entry_metadata() {
    let dir = tempfile::tempdir().unwrap();
    fs::write(dir.path().join("file.txt"), "content").unwrap();

    for entry in fs::read_dir(dir.path()).unwrap() {
        let entry = entry.unwrap();
        let meta = mad_hatter::ioutil::entry_metadata(&entry).unwrap();
        assert!(meta.is_file());
    }
}

#[test]
fn test_entry_metadata_dir() {
    let dir = tempfile::tempdir().unwrap();
    fs::create_dir(dir.path().join("subdir")).unwrap();

    for entry in fs::read_dir(dir.path()).unwrap() {
        let entry = entry.unwrap();
        let meta = mad_hatter::ioutil::entry_metadata(&entry).unwrap();
        assert!(meta.is_dir());
    }
}