// The upstream tests reach the internal OarFile.LoadTerrain member via reflection.
// Keep the equivalent Rust seam private to the owning crate.
// BSD-3-Clause source (see LICENSE.md): LibreMetaverse.Tests/OarFileTerrainTests.cs
// SHA-256: 19c42f7f132b97dc1667208f1e9b49df8ff6db96265c22b1c1ef5498e3c5c75d

#![allow(clippy::float_cmp)]

use crate::assets::OarFile;
use std::sync::{Arc, Mutex};

fn raw_terrain(side: usize, fill: f32) -> Vec<u8> {
    fill.to_le_bytes().repeat(side * side)
}

// Fixture SHA-256: fcdd41fbadfe6a69d9687b3777692c2de82c831856fa8bcef978c3c17b0117fa
// parity-case: LibreMetaverse.Tests/OarFileTerrainTests.cs::OarFileTerrainTests.LoadTerrain_StandardRegion_Loads256x256::test c4e3a994baf06b0106a6614e9c3efbcc27e45ff1725f5470d2db6ded1fff6014 translated
#[test]
fn load_standard_region_terrain() {
    let data = raw_terrain(256, 21.0);
    let total_bytes = i64::try_from(data.len()).expect("terrain byte count fits i64");
    let captured = Arc::new(Mutex::new(None));
    let callback_capture = Arc::clone(&captured);
    let loaded = OarFile::load_terrain(
        "terrains/region.r32",
        data,
        Box::new(move |terrain, _, _| {
            *callback_capture.lock().expect("terrain capture") = Some(terrain);
        }),
        0,
        total_bytes,
    )
    .expect("OarFile.LoadTerrain");
    assert!(loaded);
    let terrain = captured
        .lock()
        .expect("terrain capture")
        .take()
        .expect("terrain callback");
    assert_eq!(terrain.len(), 256);
    assert!(terrain.iter().all(|row| row.len() == 256));
    assert_eq!(terrain[0][0], 21.0);
}

// Fixture SHA-256: c07500b6f966d65dda9261e3e701fb5bb13e31239ff3a89d74c0046d0ba4ec12
// parity-case: LibreMetaverse.Tests/OarFileTerrainTests.cs::OarFileTerrainTests.LoadTerrain_Varregion_Loads512x512::test 4820338f10acbb4987e26992d7a7957be58ab6bc548674bf18943ef312962894 translated
#[test]
fn load_varregion_terrain() {
    let data = raw_terrain(512, 30.0);
    let total_bytes = i64::try_from(data.len()).expect("terrain byte count fits i64");
    let captured = Arc::new(Mutex::new(None));
    let callback_capture = Arc::clone(&captured);
    let loaded = OarFile::load_terrain(
        "terrains/megaregion.f32",
        data,
        Box::new(move |terrain, _, _| {
            *callback_capture.lock().expect("terrain capture") = Some(terrain);
        }),
        0,
        total_bytes,
    )
    .expect("OarFile.LoadTerrain");
    assert!(loaded);
    let terrain = captured
        .lock()
        .expect("terrain capture")
        .take()
        .expect("terrain callback");
    assert_eq!(terrain.len(), 512);
    assert!(terrain.iter().all(|row| row.len() == 512));
}

// Fixture SHA-256: 2dc88437e482fdaa5613df885d49c2b19bd623ecfc387a72338d2367d4b3b451
// parity-case: LibreMetaverse.Tests/OarFileTerrainTests.cs::OarFileTerrainTests.LoadTerrain_WrongByteCount_FailsGracefully::test ff6fb4feb2773c93397d412d0ecf6aef1f3636e823dabb729a7a6cbe94d1513f translated
#[test]
fn reject_terrain_with_wrong_byte_count() {
    let data = vec![0; 256_usize * 256 * 4 + 3];
    let total_bytes = i64::try_from(data.len()).expect("terrain byte count fits i64");
    let captured = Arc::new(Mutex::new(None));
    let callback_capture = Arc::clone(&captured);
    let loaded = OarFile::load_terrain(
        "terrains/broken.r32",
        data,
        Box::new(move |terrain, _, _| {
            *callback_capture.lock().expect("terrain capture") = Some(terrain);
        }),
        0,
        total_bytes,
    )
    .expect("OarFile.LoadTerrain");
    assert!(!loaded);
    assert!(captured.lock().expect("terrain capture").is_none());
}

// Fixture SHA-256: 9b94b83334ada38b48b53f19ef2c45abc9f84fb723564671290a556f75d6fdc8
// parity-case: LibreMetaverse.Tests/OarFileTerrainTests.cs::OarFileTerrainTests.LoadTerrain_NonSquarePostCount_FailsGracefully::test 218754e53232cd10318668c70b94ae9d7d541d09598b0490082e023e76d6045f translated
#[test]
fn reject_terrain_with_non_square_post_count() {
    let data = vec![0; 257_usize * 256 * 4];
    let total_bytes = i64::try_from(data.len()).expect("terrain byte count fits i64");
    let captured = Arc::new(Mutex::new(None));
    let callback_capture = Arc::clone(&captured);
    let loaded = OarFile::load_terrain(
        "terrains/nonsquare.r32",
        data,
        Box::new(move |terrain, _, _| {
            *callback_capture.lock().expect("terrain capture") = Some(terrain);
        }),
        0,
        total_bytes,
    )
    .expect("OarFile.LoadTerrain");
    assert!(!loaded);
    assert!(captured.lock().expect("terrain capture").is_none());
}
