#include "register_types.h"
#include "character_unit.hpp"
#include "character_world_state.hpp"
#include "enemy_world_state.hpp"
#include "entity_health.hpp"
#include "inventory.hpp"
#include "item_db.hpp"
#include "nav_marker.hpp"
#include "nav_room.hpp"
#include "rts_actions.hpp"
#include "rts_game_mode.hpp"
#include "rts_items.hpp"
#include "rts_player.hpp"
#include "rts_states.hpp"
#include "tank_unit.hpp"
#include "unit.hpp"
#include "unit_world_state.hpp"
#include "goap/action.hpp"
#include "goap/action_db.hpp"
#include "goap/actor_world_state.hpp"
#include "goap/goal.hpp"
#include "goap/planner.hpp"
#include "goap/state.hpp"
#include "utils/register_types.hpp"
#include <gdextension_interface.h>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>

namespace gd = godot;

void initialize_gdextension_types(gd::ModuleInitializationLevel p_level)
{
    if (p_level != gd::MODULE_INITIALIZATION_LEVEL_SCENE) {
        return;
    }
    utils::godot_cpp_utils_register_types();

    // always register actions before classes,
    // so that ActionDB::get_enum_hint is complete before _bind_methods.
    goap::ActionDB::register_action<MoveToTarget>();
    goap::ActionDB::register_action<UseWeapon>();
    goap::ActionDB::register_action<FindTarget>();
    goap::ActionDB::register_action<GetInRange>();
    goap::ActionDB::register_action<TankSelfHeal>();
    goap::ActionDB::register_action<TakeCover>();

    // same for items,
    // make sure ItemDB::get_enum_hint is fully populated out before _bind_methods.
    ItemDB::register_item<Medkit>();
    ItemDB::register_item<Handgun>();
    ItemDB::register_item<Lasercutter>();
    ItemDB::register_item<Welder>();

    GDREGISTER_RUNTIME_CLASS(goap::ActorWorldState);
    GDREGISTER_CLASS(goap::Goal);
    GDREGISTER_RUNTIME_CLASS(goap::Planner);
    GDREGISTER_RUNTIME_CLASS(goap::State);

    GDREGISTER_RUNTIME_CLASS(MoveTo);
    GDREGISTER_RUNTIME_CLASS(Animate);
    GDREGISTER_RUNTIME_CLASS(Activate);
    GDREGISTER_RUNTIME_CLASS(UnitWorldState);
    GDREGISTER_RUNTIME_CLASS(EnemyWorldState);
    GDREGISTER_RUNTIME_CLASS(CharacterWorldState);
    GDREGISTER_RUNTIME_CLASS(GoalMarker);
    GDREGISTER_RUNTIME_CLASS(Unit);
    GDREGISTER_RUNTIME_CLASS(TankUnit)
    GDREGISTER_RUNTIME_CLASS(CharacterUnit);
    GDREGISTER_RUNTIME_CLASS(EntityHealth);
    GDREGISTER_CLASS(NavMarker);
    GDREGISTER_RUNTIME_CLASS(NavRoom);
    GDREGISTER_CLASS(Inventory);
    GDREGISTER_RUNTIME_CLASS(RTSGameMode);
    GDREGISTER_RUNTIME_CLASS(RTSPlayer);
}

extern "C"
{
    // Initialization
    GDExtensionBool GDE_EXPORT metro_rts_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization)
    {
        gd::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
        init_obj.register_initializer(initialize_gdextension_types);
        init_obj.set_minimum_library_initialization_level(gd::MODULE_INITIALIZATION_LEVEL_SCENE);

        return init_obj.init();
    }
}
