#ifndef AXE_HPP_
#define AXE_HPP_

#include <Item/StatefulItem/BasicTool/BasicTool.hpp>
#include <concepts>
#include <World/World.hpp>
#include <Block/Block.hpp>
#include <Decoration/Tree/Tree.hpp>

/**
 * @brief Represents an axe with some given properties.
 */
class Axe : public BasicTool
{
private:
    const float m_power;
    const std::string m_displayName;

    bool isEffectiveAgainst(Block &block);

    template<typename TCallback>
    requires std::invocable<TCallback&, const glm::ivec3&>
    void walkTree(World &world, glm::ivec3 pos, TCallback callback)
    {
        Block *block = world.getBlockAt(pos);
        if (block == nullptr)
        {
            return;
        }

        uint8_t meta = *world.getBlockMeta(pos);
        if (!isEffectiveAgainst(*block))
        {
            return;
        }

        if (block->name != "main:leaves" && !block->isSuffixed("Leaves") && (meta & Tree::metaNaturalLogMask) == 0)
        {
            return;
        }

        if (!callback(pos))
        {
            return;
        }

        walkTree(world, pos + glm::ivec3(-1, 0, 0), callback);
        walkTree(world, pos + glm::ivec3(1, 0, 0), callback);
        walkTree(world, pos + glm::ivec3(0, -1, 0), callback);
        walkTree(world, pos + glm::ivec3(0, 1, 0), callback);
        walkTree(world, pos + glm::ivec3(0, 0, 1), callback);
    }

public:
    Axe(std::string name, Material &mat, int numUses, float power, std::string displayName);

    virtual bool canDig(ItemStack &stack, Block &block) override;
    virtual float getPowerAgainst(ItemStack &stack, Block &block) override;
    virtual std::string getDisplayName(const ItemStack &stack) override;
    virtual void harvest(ItemStack &stack, LocalWorld &world, glm::ivec3 pos) override;
    virtual void getExtraToolTipLines(const ItemStack &stack, ToolTip &tip) override;
    virtual Sound& getDigSoundFor(ItemStack &stack, Block &block) override;
    virtual void getSelectedBlocks(
        ItemStack &stack,
        Player &player,
        World &world,
        glm::ivec3 primaryBlockPos,
        std::vector<glm::ivec3> &selectedBlocks
    ) override;
};

#endif