#ifndef RTS_UNIT_HPP
#define RTS_UNIT_HPP

#include "goal_marker.hpp"
#include "inventory.hpp"
#include "unit_world_state.hpp"
#include "goap/goal.hpp"
#include "goap/planner.hpp"
#include "utils/godot_macros.hpp"
#include <godot_cpp/classes/animation_player.hpp>
#include <godot_cpp/classes/character_body3d.hpp>
#include <godot_cpp/classes/navigation_agent3d.hpp>
#include <godot_cpp/classes/node3d.hpp>
#include <godot_cpp/variant/callable.hpp>

namespace gd = godot;

GDENUM(UnitTeam,
    Neutral,
    Player,
    Ally,
    Enemy
);

class Unit : public gd::CharacterBody3D {
    GDCLASS(Unit, gd::CharacterBody3D);
    static void _bind_methods();
public:
    virtual void _enter_tree() override;
    virtual void _physics_process(double) override;

    void stop_plan();
    void begin_marker_temporary(GoalMarker *marker);
    void begin_goal(gd::Ref<goap::Goal> goal);
    void set_target_goal(gd::Node3D *target, gd::Ref<goap::Goal> goal);

    virtual void use_weapon();
    void aim_at(gd::Node3D *node);
    void on_unconscious(Unit *damage_source);
    void on_death(Unit *damage_source);
private:
    void on_velocity_computed(gd::Vector3 vel);
    void destroy_state();
    void state_finished();
    void next_action();
    void replan_goal();
    void set_goal_and_plan(gd::Ref<goap::Goal> goal);
public: // getter-setters
    UnitWorldState *get_world_state() const;
    UnitTeam get_team() const;
    void set_configure_team(int value);
    int get_configure_team() const;
    bool has_plan() const;
    EntityHealth *get_entity_health();
    void set_movement_speed(float speed);
    float get_movement_speed() const;
private:
    gd::Callable on_state_finished{callable_mp(this, &Unit::state_finished)};
    gd::Callable on_plan_failed{callable_mp(this, &Unit::replan_goal)};
protected:
    goap::Plan current_plan{};
    gd::Ref<goap::Goal> current_goal{};
    goap::State *state{nullptr};

    UnitTeam team{UnitTeam::Neutral};
    float movement_speed{2.f};

    gd::NavigationAgent3D *agent{nullptr};
    gd::AnimationPlayer *anim_player{nullptr};
    goap::Planner *planner{nullptr};
    EntityHealth *health{nullptr};
    UnitWorldState *world_state{nullptr};
    Inventory *inventory{nullptr};
#ifdef DEBUG_ENABLED
public:
    gd::String DEBUG_print_debug_info();
#endif // DEBUG_ENABLED
};

#endif // !RTS_UNIT_HPP
