mod common;

use sqpack_rs::{Error, SqPack};

#[test]
#[ignore = "requires real FFXIV install; run with `cargo test -- --ignored`"]
fn opens_real_install() {
    let Some(data_dir) = common::maybe_data_dir() else {
        eprintln!("skipping: no sqpack data available (set SQPACK_TEST_DATA_DIR)");
        return;
    };
    let Some(install_root) = common::install_root_from_data_dir(&data_dir) else {
        eprintln!(
            "skipping: could not derive install root from {}",
            data_dir.display()
        );
        return;
    };

    let sq = SqPack::open(&install_root).expect("SqPack::open should succeed on a real install");

    assert_eq!(
        sq.install_root(),
        install_root.as_path(),
        "install_root() must echo the path passed to open()"
    );
    assert_eq!(
        sq.platform(),
        sqpack_rs::Platform::Win32,
        "open() must default to Win32"
    );
    eprintln!("opened install at {}", install_root.display());
}

#[test]
#[ignore = "requires real FFXIV install; run with `cargo test -- --ignored`"]
fn reads_root_exl() {
    let Some(data_dir) = common::maybe_data_dir() else {
        eprintln!("skipping: no sqpack data available (set SQPACK_TEST_DATA_DIR)");
        return;
    };
    let Some(install_root) = common::install_root_from_data_dir(&data_dir) else {
        eprintln!("skipping: could not derive install root");
        return;
    };

    let sq = SqPack::open(&install_root).expect("open");
    let bytes = sq
        .read_file("exd/root.exl")
        .expect("read_file(exd/root.exl)");

    assert!(!bytes.is_empty(), "exd/root.exl must not be empty");
    assert_eq!(
        &bytes[..4],
        b"EXLT",
        "exd/root.exl should begin with the EXLT magic"
    );
    eprintln!("exd/root.exl: {} bytes", bytes.len());
}

#[test]
#[ignore = "requires real FFXIV install; run with `cargo test -- --ignored`"]
fn reads_an_exh_file() {
    let Some(data_dir) = common::maybe_data_dir() else {
        eprintln!("skipping: no sqpack data available (set SQPACK_TEST_DATA_DIR)");
        return;
    };
    let Some(install_root) = common::install_root_from_data_dir(&data_dir) else {
        eprintln!("skipping: could not derive install root");
        return;
    };

    let sq = SqPack::open(&install_root).expect("open");

    let candidates = [
        "exd/achievement.exh",
        "exd/item.exh",
        "exd/territorytype.exh",
    ];

    let mut found_ok = false;
    for path in candidates {
        match sq.read_file(path) {
            Ok(bytes) => {
                assert!(!bytes.is_empty(), "{path}: payload must not be empty");
                eprintln!("{path}: {} bytes", bytes.len());
                found_ok = true;
                break;
            }
            Err(Error::UnsupportedFileKind { kind }) => {
                eprintln!("{path}: UnsupportedFileKind({kind:?}) — skipping");
            }
            Err(Error::PathNotFound { .. }) => {
                eprintln!("{path}: PathNotFound — skipping");
            }
            Err(other) => {
                panic!("{path}: unexpected error: {other}");
            }
        }
    }

    if !found_ok {
        eprintln!(
            "reads_an_exh_file: all candidates returned non-Standard or not-found; routing appears correct"
        );
    }
}

mod lumina_reference {
    pub const ROOT_EXL_PATH: &str = "exd/root.exl";
    pub const ROOT_EXL_SHA256: &str =
        "6e0053c2e171fa931a167368631990cb9b8f3f969049d5637a492d901ee8ae25";
    pub const ROOT_EXL_LEN: usize = 238_923;

    pub const ITEM_EXH_PATH: &str = "exd/item.exh";
    pub const ITEM_EXH_SHA256: &str =
        "37afe365a3c8e08949dbb55a321add44e42144bc703c510398a97b8687453d88";
    pub const ITEM_EXH_LEN: usize = 1_258;
}

#[test]
#[ignore = "requires real FFXIV install; run with `cargo test -- --ignored`"]
fn read_file_matches_lumina_byte_for_byte() {
    use sha2::{Digest, Sha256};

    let Some(data_dir) = common::maybe_data_dir() else {
        eprintln!("skipping: no sqpack data available (set SQPACK_TEST_DATA_DIR)");
        return;
    };
    let Some(install_root) = common::install_root_from_data_dir(&data_dir) else {
        eprintln!("skipping: could not derive install root");
        return;
    };

    let sq = SqPack::open(&install_root).expect("open");

    for (path, expected_sha, expected_len) in [
        (
            lumina_reference::ROOT_EXL_PATH,
            lumina_reference::ROOT_EXL_SHA256,
            lumina_reference::ROOT_EXL_LEN,
        ),
        (
            lumina_reference::ITEM_EXH_PATH,
            lumina_reference::ITEM_EXH_SHA256,
            lumina_reference::ITEM_EXH_LEN,
        ),
    ] {
        let bytes = sq
            .read_file(path)
            .unwrap_or_else(|e| panic!("read_file({path}): {e}"));

        assert_eq!(
            bytes.len(),
            expected_len,
            "{path}: payload length differs from Lumina ({} bytes vs expected {expected_len}). \
             Either the install has updated past the captured patch level (re-capture the \
             reference values) or our reader has a content-bug.",
            bytes.len(),
        );

        let actual_sha = format!("{:x}", Sha256::digest(&bytes));
        assert_eq!(
            actual_sha, expected_sha,
            "{path}: payload bytes differ from Lumina. Length matched ({expected_len}) but the \
             content diverged — either the install has updated past the captured patch level \
             (re-capture the reference values) or our reader has a subtle content-bug.",
        );

        eprintln!("{path}: {} bytes, sha256 matches Lumina", bytes.len());
    }
}

#[test]
#[ignore = "requires real FFXIV install; run with `cargo test -- --ignored`"]
fn unknown_path_is_path_not_found() {
    let Some(data_dir) = common::maybe_data_dir() else {
        eprintln!("skipping: no sqpack data available (set SQPACK_TEST_DATA_DIR)");
        return;
    };
    let Some(install_root) = common::install_root_from_data_dir(&data_dir) else {
        eprintln!("skipping: could not derive install root");
        return;
    };

    let sq = SqPack::open(&install_root).expect("open");
    let err = sq.read_file("exd/this_does_not_exist_xyz.exh").unwrap_err();
    match err {
        Error::PathNotFound { game_path } => {
            assert_eq!(game_path, "exd/this_does_not_exist_xyz.exh");
        }
        other => panic!("expected PathNotFound, got {other:?}"),
    }
}

#[test]
#[ignore = "requires real FFXIV install; run with `cargo test -- --ignored`"]
fn unknown_category_is_unknown_category() {
    let Some(data_dir) = common::maybe_data_dir() else {
        eprintln!("skipping: no sqpack data available (set SQPACK_TEST_DATA_DIR)");
        return;
    };
    let Some(install_root) = common::install_root_from_data_dir(&data_dir) else {
        eprintln!("skipping: could not derive install root");
        return;
    };

    let sq = SqPack::open(&install_root).expect("open");
    let err = sq.read_file("notacategory/foo.bin").unwrap_err();
    match err {
        Error::UnknownCategory { name } => {
            assert_eq!(name, "notacategory");
        }
        other => panic!("expected UnknownCategory, got {other:?}"),
    }
}
