import unreal


MAP_PATH = "/Game/Agrarian/Maps/L_GroundZeroTerrain_Test"
CHARACTER_CLASS_PATH = "/Game/Agrarian/Blueprints/Characters/BP_AgrarianPlayerCharacter"
RABBIT_LABELS = ["AGR_DemoRabbitWildlife_01", "AGR_RabbitWildlife_01"]


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


def load_blueprint_class(path):
    generated_class = unreal.EditorAssetLibrary.load_blueprint_class(path)
    if not generated_class:
        raise RuntimeError(f"Could not load Blueprint class: {path}")
    return generated_class


def find_actor_by_label(label):
    for actor in unreal.EditorLevelLibrary.get_all_level_actors():
        if get_actor_label(actor) == label:
            return actor
    return None


def find_actor_by_any_label(labels):
    for label in labels:
        actor = find_actor_by_label(label)
        if actor:
            return actor
    return None


def enum_name(value):
    return str(value).split(".")[-1].lower()


def get_bool_property(actor, *property_names):
    for property_name in property_names:
        try:
            return bool(actor.get_editor_property(property_name))
        except Exception:
            continue
    raise RuntimeError(f"Could not read any bool property from {property_names}")


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

    character_class = load_blueprint_class(CHARACTER_CLASS_PATH)
    rabbit = find_actor_by_any_label(RABBIT_LABELS)
    if not rabbit:
        raise RuntimeError(f"Could not find placed rabbit wildlife by labels: {RABBIT_LABELS}")

    character = unreal.AgrarianEditorAutomationLibrary.spawn_actor_in_editor_world(
        character_class,
        unreal.Vector(500.0, 320.0, 180.0),
        unreal.Rotator(0.0, 0.0, 0.0),
        "AGR_AutomationWildlifeCharacter",
    )
    if not character:
        raise RuntimeError("Could not spawn automation character")

    inventory = character.get_component_by_class(unreal.AgrarianInventoryComponent)
    if not inventory:
        raise RuntimeError("Automation character is missing AgrarianInventoryComponent")

    starting_health = float(rabbit.get_editor_property("health"))
    max_health = float(rabbit.get_editor_property("max_health"))
    if starting_health <= 0.0 or max_health <= 0.0:
        raise RuntimeError(f"Rabbit starts invalid health={starting_health}, max_health={max_health}")

    rabbit.apply_wildlife_damage(1.0, character)
    damaged_health = float(rabbit.get_editor_property("health"))
    damaged_state = enum_name(rabbit.get_editor_property("wildlife_state"))
    if not damaged_health < starting_health:
        raise RuntimeError(f"Rabbit non-lethal damage did not reduce health: {starting_health} -> {damaged_health}")
    if "fleeing" not in damaged_state:
        raise RuntimeError(f"Rabbit expected fleeing after non-lethal damage, got {damaged_state}")

    rabbit.apply_wildlife_damage(max_health + 10.0, character)
    dead_health = float(rabbit.get_editor_property("health"))
    dead_state = enum_name(rabbit.get_editor_property("wildlife_state"))
    if dead_health != 0.0:
        raise RuntimeError(f"Rabbit lethal damage expected health 0, got {dead_health}")
    if "dead" not in dead_state:
        raise RuntimeError(f"Rabbit expected dead after lethal damage, got {dead_state}")
    if not rabbit.can_interact(character):
        raise RuntimeError("Rabbit should be harvestable after death")

    meat_before = inventory.get_item_count("meat")
    hide_before = inventory.get_item_count("hide")
    rabbit.interact(character)
    meat_after = inventory.get_item_count("meat")
    hide_after = inventory.get_item_count("hide")
    if meat_after <= meat_before:
        raise RuntimeError(f"Rabbit harvest did not add meat: {meat_before} -> {meat_after}")
    if hide_after <= hide_before:
        raise RuntimeError(f"Rabbit harvest did not add hide: {hide_before} -> {hide_after}")
    if not get_bool_property(rabbit, "b_harvested", "harvested"):
        raise RuntimeError("Rabbit harvest did not set bHarvested")
    if rabbit.can_interact(character):
        raise RuntimeError("Rabbit should not be harvestable twice")

    unreal.EditorLevelLibrary.destroy_actor(character)
    unreal.log(
        "PASS: wildlife damage/death/harvest verified "
        f"health {starting_health}->{damaged_health}->0, "
        f"meat {meat_before}->{meat_after}, hide {hide_before}->{hide_after}"
    )


main()
