mod common;

use sqpack_rs::sklb::{Sklb, SklbVersion};
use sqpack_rs::{DatFile, Index, SqPackPayload};

const HAVOK_MAGIC_PATTERNS: [[u8; 4]; 4] = [
    0xCAB0_0D1Eu32.to_le_bytes(),
    0xCAB0_0D1Eu32.to_be_bytes(),
    0xD011_FACEu32.to_le_bytes(),
    0xD011_FACEu32.to_be_bytes(),
];

fn looks_like_sklb(bytes: &[u8]) -> bool {
    bytes.len() >= 4 && &bytes[0..4] == b"blks"
}

fn looks_like_havok_tagfile(bytes: &[u8]) -> bool {
    if bytes.len() < 4 {
        return false;
    }
    HAVOK_MAGIC_PATTERNS
        .iter()
        .any(|pat| &bytes[0..4] == pat.as_slice())
}

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

    let dat_path = data_dir.join("040000.win32.dat0");
    let idx_path = data_dir.join("040000.win32.index");

    if !dat_path.exists() || !idx_path.exists() {
        eprintln!("skipping: 040000.win32.dat0 or .index not found");
        return;
    }

    let idx = Index::open(&idx_path).expect("Index::open");
    let mut dat = DatFile::open(&dat_path).expect("DatFile::open");

    let mut checked = 0usize;
    let target = 3usize;
    let mut sklb_count = 0usize;

    'outer: for entry in idx
        .entries()
        .iter()
        .filter(|e| !e.is_synonym() && e.data_file_id() == 0)
        .take(5000)
    {
        let Ok(SqPackPayload::Standard(payload)) = dat.read_file_typed(entry.byte_offset()) else {
            continue;
        };

        if !looks_like_sklb(&payload) {
            continue;
        }
        sklb_count += 1;

        let sklb = match Sklb::parse(&payload) {
            Ok(s) => s,
            Err(e) => panic!("Sklb::parse failed for hash {:#018x}: {e}", entry.hash),
        };

        let version = sklb.version();
        assert!(
            matches!(version, SklbVersion::V1 | SklbVersion::V2),
            "version must be V1 or V2, got {version:?}"
        );

        let havok = sklb.havok_bytes();
        assert!(
            !havok.is_empty(),
            "havok_bytes must be non-empty for hash {:#018x}",
            entry.hash
        );
        assert!(
            looks_like_havok_tagfile(havok),
            "havok_bytes for hash {:#018x} must start with a known Havok tagfile magic, \
             got {:02X?}",
            entry.hash,
            &havok[..4],
        );

        checked += 1;
        eprintln!(
            "  sklb {checked}: hash={:#018x} version={version:?} \
             layer_offset={:#x} havok_offset={:#x} havok_len={}",
            entry.hash,
            sklb.layer_offset(),
            sklb.havok_offset(),
            havok.len(),
        );
        if checked >= target {
            break 'outer;
        }
    }

    eprintln!(
        "scanned_sklb: found {sklb_count} sklb-magic entry/entries in first 5000 entries of \
         040000.win32 ({checked} structurally validated)"
    );
}
