#ifndef ITEM_HPP
#define ITEM_HPP

#include "stats.hpp"
#include "goap/action.hpp"
#include "utils/godot_macros.hpp"
#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

namespace gd = godot;

GDENUM(ItemCapability,
    Heal,
    Revive,
    WeaponEquip,
    WeaponRanged,
    WeaponMelee,
    ArmourEquip,
    HeadEquip,
    UtilityEquip,
    Consume
);

typedef int ItemID;
class Unit;

class Item {
friend class ItemDB;
public:
    static gd::StringName get_static_class() {
        gd::UtilityFunctions::push_error("Calling Item::get_static_class() on an Item class that does not implement it. Use ITEM_CLASS(*) macro.");
        return "Item";
    }
    virtual gd::StringName get_class() const {
        gd::UtilityFunctions::push_error("Calling Item::get_class() on an Item class that does not implement it. Use ITEM_CLASS(*) macro.");
        return "Item";
    }
    virtual gd::String get_display_name() const {
        gd::UtilityFunctions::push_error("Calling Item::get_display_name() on an Item class that does not implement it. Use ITEM_CLASS(*) macro.");
        return "<UNNAMED ITEM>";
    }
    virtual gd::String get_description() const {
        gd::UtilityFunctions::push_error("Calling Item::get_description() on an Item class that does not implement it. Use ITEM_CLASS(*) macro.");
        return "<UNDESCRIBED>";
    }
    Item() = default;
    virtual ~Item();
public:
    virtual bool can_use_on(Unit *used_by, gd::Object *used_on) const;
    bool try_use_on(Unit *used_by, gd::Object *used_on) const;
    virtual Stats get_stats() const;
    bool has_capability(ItemCapability const &capability) const;
    ItemID get_id() const;
protected:
    virtual void use_on(Unit *used_by, gd::Object *used_on) const;
protected:
    gd::HashSet<uint32_t> capabilities{};
private:
    ItemID id{-1};
};

#define ITEM_CLASS(Class_, DisplayName_, Description_)\
public: \
    _FORCE_INLINE_ static godot::StringName get_static_class() { return #Class_; }\
    _FORCE_INLINE_ virtual godot::StringName get_class() const override { return #Class_; }\
    _FORCE_INLINE_ virtual godot::String get_display_name() const override { return DisplayName_; }\
    _FORCE_INLINE_ virtual godot::String get_description() const override { return Description_; }\
private:

#endif // !ITEM_HPP
