from pathlib import Path

import unreal


MAP_PATH = "/Game/Agrarian/Maps/L_GroundZeroTerrain_Test"
PROJECT_ROOT = Path(unreal.Paths.convert_relative_path_to_full(unreal.Paths.project_dir()))
PLACEHOLDER_MESH_FOLDER = "/Game/Agrarian/Environment/PlaceholderMeshes"
PLACEHOLDER_MESHES = {
    "SM_AGR_Placeholder_Cube",
    "SM_AGR_Placeholder_ChamferCube",
    "SM_AGR_Placeholder_Cylinder",
    "SM_AGR_Placeholder_QuarterCylinder",
    "SM_AGR_Placeholder_Plane",
}
BLUEPRINT_PATHS = [
    "/Game/Agrarian/Blueprints/Resources/BP_WoodResourceNode",
    "/Game/Agrarian/Blueprints/Resources/BP_FiberResourceNode",
    "/Game/Agrarian/Blueprints/Resources/BP_StoneResourceNode",
    "/Game/Agrarian/Blueprints/Structures/BP_Campfire",
    "/Game/Agrarian/Blueprints/Structures/BP_PrimitiveShelter",
    "/Game/Agrarian/Blueprints/World/BP_FreshWaterSource",
]
DOC_SNIPPETS = [
    (PROJECT_ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md", "[x] Replace `LevelPrototyping` cube/cylinder mesh dependencies"),
    (PROJECT_ROOT / "Docs" / "Terrain" / "GroundZeroNaturalEnvironmentPass.md", "Agrarian-native placeholder"),
]


def asset_path(asset):
    if not asset:
        return ""
    return asset.get_path_name().split(".", 1)[0]


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


def assert_native_mesh(path, failures):
    if not path.startswith(PLACEHOLDER_MESH_FOLDER):
        failures.append(f"expected native Agrarian placeholder mesh, got {path}")
    if "LevelPrototyping" in path:
        failures.append(f"template mesh reference remains: {path}")


def main():
    failures = []

    for mesh_name in PLACEHOLDER_MESHES:
        mesh_path = f"{PLACEHOLDER_MESH_FOLDER}/{mesh_name}"
        if not unreal.EditorAssetLibrary.does_asset_exist(mesh_path):
            failures.append(f"missing native placeholder mesh asset: {mesh_path}")

    for blueprint_path in BLUEPRINT_PATHS:
        generated_class = unreal.EditorAssetLibrary.load_blueprint_class(blueprint_path)
        if not generated_class:
            failures.append(f"could not load Blueprint class: {blueprint_path}")
            continue

        cdo = unreal.get_default_object(generated_class)
        mesh_component = cdo.get_editor_property("mesh")
        assert_native_mesh(asset_path(mesh_component.get_editor_property("static_mesh")), failures)

    if not unreal.EditorLevelLibrary.load_level(MAP_PATH):
        failures.append(f"could not load map: {MAP_PATH}")
    else:
        actors = unreal.EditorLevelLibrary.get_all_level_actors()
        foliage_actors = [
            actor
            for actor in actors
            if get_actor_label(actor) == "AGR_GroundZeroFoliage_FirstPass"
        ]
        if len(foliage_actors) != 1:
            failures.append(f"expected one AGR_GroundZeroFoliage_FirstPass, found {len(foliage_actors)}")
        else:
            for property_name in ("tree_instances", "shrub_instances", "grass_instances"):
                component = foliage_actors[0].get_editor_property(property_name)
                assert_native_mesh(asset_path(component.get_editor_property("static_mesh")), failures)

        for actor in actors:
            label = get_actor_label(actor)
            if not label.startswith("AGR_GZ_EnvVar_"):
                continue

            mesh_components = actor.get_components_by_class(unreal.StaticMeshComponent)
            if not mesh_components:
                failures.append(f"{label} has no static mesh component")
                continue
            assert_native_mesh(asset_path(mesh_components[0].get_editor_property("static_mesh")), failures)

    for path, snippet in DOC_SNIPPETS:
        text = path.read_text(encoding="utf-8")
        if snippet not in text:
            failures.append(f"{path} missing `{snippet}`")

    if failures:
        raise RuntimeError("Native placeholder mesh verification failed: " + "; ".join(failures))

    unreal.log(
        "Native placeholder mesh verification complete: "
        f"{len(PLACEHOLDER_MESHES)} Agrarian mesh assets, {len(BLUEPRINT_PATHS)} Blueprint meshes, "
        "foliage meshes, and environment variation meshes use native paths."
    )


main()
