import unreal


MAP_PATH = "/Game/Agrarian/Maps/L_GroundZeroTerrain_Test"

EXPECTED_PLACEMENTS = {
    "AGR_WoodResourceNode_01": {
        "class_path": "/Game/Agrarian/Blueprints/Resources/BP_WoodResourceNode",
        "location": unreal.Vector(650.0, -150.0, 120.0),
        "properties": {
            "remaining_harvests": 16,
            "quantity_per_harvest": 2,
        },
    },
    "AGR_FiberResourceNode_01": {
        "class_path": "/Game/Agrarian/Blueprints/Resources/BP_FiberResourceNode",
        "location": unreal.Vector(560.0, 140.0, 90.0),
        "properties": {
            "remaining_harvests": 10,
            "quantity_per_harvest": 3,
        },
    },
    "AGR_Campfire_01": {
        "class_path": "/Game/Agrarian/Blueprints/Structures/BP_Campfire",
        "location": unreal.Vector(900.0, 120.0, 60.0),
        "properties": {
            "fuel_seconds": 180.0,
            "warmth_radius": 650.0,
        },
    },
    "AGR_PrimitiveShelter_01": {
        "class_path": "/Game/Agrarian/Blueprints/Structures/BP_PrimitiveShelter",
        "location": unreal.Vector(1200.0, -260.0, 140.0),
        "properties": {
            "weather_protection": 0.7,
        },
    },
    "AGR_RabbitWildlife_01": {
        "class_path": "/Game/Agrarian/Blueprints/Wildlife/BP_RabbitWildlife",
        "location": unreal.Vector(450.0, 420.0, 100.0),
        "properties": {
            "wildlife_id": "rabbit",
            "max_health": 12.0,
        },
    },
}


def nearly_equal(left, right):
    return abs(float(left) - float(right)) < 0.001


def vectors_close(left, right):
    return (
        abs(left.x - right.x) < 0.1
        and abs(left.y - right.y) < 0.1
        and abs(left.z - right.z) < 0.1
    )


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}")

    failures = []
    actors_by_label = {get_actor_label(actor): actor for actor in unreal.EditorLevelLibrary.get_all_level_actors()}

    for label, expected in EXPECTED_PLACEMENTS.items():
        actor = actors_by_label.get(label)
        if not actor:
            failures.append(f"{label} missing")
            continue

        actor_location = actor.get_actor_location()
        if not vectors_close(actor_location, expected["location"]):
            failures.append(f"{label} expected location {expected['location']}, got {actor_location}")

        for property_name, expected_value in expected.get("properties", {}).items():
            actual_value = actor.get_editor_property(property_name)
            if isinstance(expected_value, (int, float)):
                if not nearly_equal(actual_value, expected_value):
                    failures.append(f"{label} {property_name} expected {expected_value}, got {actual_value}")
            elif str(actual_value) != expected_value:
                failures.append(f"{label} {property_name} expected {expected_value}, got {actual_value}")

    if failures:
        raise RuntimeError("Test map placement verification failed: " + "; ".join(failures))

    unreal.log("Agrarian test map placement verification complete.")


main()
