#ifndef GOAP_ACTION_HPP
#define GOAP_ACTION_HPP

#include "actor_world_state.hpp"
#include "state.hpp"
#include <godot_cpp/templates/hash_map.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

#define GOAP_ACTION(Name_) \
public: \
    _FORCE_INLINE_ static gd::StringName get_static_class() { return #Name_; }\
    _FORCE_INLINE_ virtual gd::StringName get_class() const override { return #Name_; }\
private:

namespace goap {
typedef int ActionID;

/*! A goap action construct.
 *
 * Child classes an be registered with `ActionDB::register_action`
 */
class Action {
    friend class ActionDB;
public:
    static gd::StringName get_static_class() {
        gd::UtilityFunctions::push_error("Action::get_static_class has been called on a class where it is not implemented");
        return "Action";
    }
    virtual gd::StringName get_class() const {
        gd::UtilityFunctions::push_error("Action::get_class has been called on a class where it is not implemented");
        return "Action";
    }

    virtual ~Action();
    virtual State *get_apply_state(ActorWorldState *context) const = 0;

    bool is_completed(ActorWorldState *context) const;
    bool is_possible(ActorWorldState *context) const;
    virtual bool procedural_is_possible(ActorWorldState *context) const;
    virtual bool procedural_is_completed(ActorWorldState *context) const;

    WorldState const &get_required() const;
    WorldState const &get_effects() const;

    ActionID get_id() const;
    bool get_require_state_complete() const;
protected:
    Action() = default;
    template<class TState>
    TState *create_state() const;
protected:
    WorldState blocking_required{};
    WorldState required{};
    WorldState effects{};
    bool only_proc_is_completed{false};
    bool require_state_complete{true};
private:
    ActionID id{-1};
};

template <class TState>
TState *Action::create_state() const {
    TState *state = memnew(TState);
    state->action = this;
    return state;
}
}

#endif // !GOAP_ACTION_HPP
