import json
from pathlib import Path

import unreal


MAP_PATH = "/Game/Agrarian/Maps/L_GroundZeroTerrain_Test"
PROJECT_ROOT = Path(r"Z:\AgrarianGameBulid")
TILE_ID = "gz_us_ca_pacifica_utm10n_e544_n4160"
METADATA_PATH = PROJECT_ROOT / "Data" / "Terrain" / "Unreal" / TILE_ID / f"{TILE_ID}_unreal_heightmap_metadata.json"
LANDSCAPE_LABEL = "AGR_GroundZero_Landscape"


def nearly_equal(left, right, tolerance=0.01):
    return abs(float(left) - float(right)) <= tolerance


def get_actor_label(actor):
    try:
        return actor.get_actor_label()
    except Exception:
        return actor.get_name()


def main():
    if not unreal.EditorLevelLibrary.load_level(MAP_PATH):
        raise RuntimeError(f"Could not load map: {MAP_PATH}")

    with METADATA_PATH.open("r", encoding="utf-8") as metadata_file:
        metadata = json.load(metadata_file)

    expected = metadata["unreal_landscape_import"]
    actors = unreal.EditorLevelLibrary.get_all_level_actors()
    landscapes = [actor for actor in actors if get_actor_label(actor) == LANDSCAPE_LABEL]
    if len(landscapes) != 1:
        raise RuntimeError(f"Expected exactly one {LANDSCAPE_LABEL}, found {len(landscapes)}")

    landscape = landscapes[0]
    scale = landscape.get_actor_scale3d()
    failures = []
    if not nearly_equal(scale.x, expected["x_scale_cm"]):
        failures.append(f"X scale expected {expected['x_scale_cm']}, got {scale.x}")
    if not nearly_equal(scale.y, expected["y_scale_cm"]):
        failures.append(f"Y scale expected {expected['y_scale_cm']}, got {scale.y}")
    if not nearly_equal(scale.z, expected["z_scale_cm"]):
        failures.append(f"Z scale expected {expected['z_scale_cm']}, got {scale.z}")

    bounds_origin, bounds_extent = landscape.get_actor_bounds(False)
    expected_extent = float(expected["tile_world_size_m"]) * 100.0 * 0.5
    if not nearly_equal(bounds_extent.x, expected_extent, tolerance=150.0):
        failures.append(f"X extent expected about {expected_extent}, got {bounds_extent.x}")
    if not nearly_equal(bounds_extent.y, expected_extent, tolerance=150.0):
        failures.append(f"Y extent expected about {expected_extent}, got {bounds_extent.y}")
    if abs(bounds_origin.x) > 150.0 or abs(bounds_origin.y) > 150.0:
        failures.append(f"Bounds origin expected near XY zero, got {bounds_origin}")

    if failures:
        raise RuntimeError("Ground Zero terrain verification failed: " + "; ".join(failures))

    unreal.log(
        "Ground Zero terrain verification complete: "
        f"scale={scale}, bounds_origin={bounds_origin}, bounds_extent={bounds_extent}"
    )


main()
