#include <BlockRegistry/BlockRegistry.hpp>
#include <Item/StatelessItem/BasicItem/Dye/Dye.hpp>
#include <World/LocalWorld/LocalWorld.hpp>
#include <Block/Block.hpp>

std::vector<std::string> Dye::colorNames = {
    "blue",
    "red",
    "green",
    "lime",
    "darkGreen",
    "yellowGreen",
    "yellow",
    "brown",
    "black",
    "magenta",
    "cyan",
    "lightRed",
    "lightYellow",
    "coral",
    "orange",
    "darkYellow",
    "teal",
    "darkBlue",
    "pink",
    "darkPink",
    "redOrange",
    "darkRed",
    "darkBrown",
    "violet",
    "purple",
    "white",
};

std::unordered_map<std::string, std::string> Dye::colorDisplayNames = {
    {"blue", "Blue"},
    {"red", "Red"},
    {"green", "Green"},
    {"lime", "Lime"},
    {"darkGreen", "Dark Green"},
    {"yellowGreen", "Yellow-green"},
    {"yellow", "Yellow"},
    {"brown", "Brown"},
    {"black", "Black"},
    {"magenta", "Magenta"},
    {"cyan", "Cyan"},
    {"lightRed", "Light Red"},
    {"lightYellow", "Light Yellow"},
    {"coral", "Coral"},
    {"orange", "Orange"},
    {"darkYellow", "Dark Yellow"},
    {"teal", "Teal"},
    {"darkBlue", "Dark Blue"},
    {"pink", "Pink"},
    {"darkPink", "Dark Pink"},
    {"redOrange", "Red-orange"},
    {"darkRed", "Dark Red"},
    {"darkBrown", "Dark Brown"},
    {"violet", "Violet"},
    {"purple", "Purple"},
    {"white", "White"},
};

std::string Dye::getDyedBlockName(const std::string &currentName)
{
    static std::unordered_map<std::string, const char*> blockToDyedMap = {
        {"main:glass", "main:$+Glass"},
        {"main:glassSlab", "main:$+GlassSlab"},
        {"main:glassStairs", "main:$+GlassStairs"},
        {"main:clay", "main:$+Clay"},
        {"main:claySlab", "main:$+ClaySlab"},
        {"main:clayStairs", "main:$+ClayStairs"},
        {"main:bricks", "main:$+Bricks"},
        {"main:bricksSlab", "main:$+BricksSlab"},
        {"main:bricksStairs", "main:$+BricksStairs"},
        {"main:planks", "main:$+Planks"},
        {"main:planksStairs", "main:$+PlanksStairs"},
        {"main:planksSlab", "main:$+PlanksSlab"},
        {"main:woodenPole", "main:$+WoodenPole"},
    };

    auto it = blockToDyedMap.find(currentName);
    if (it != blockToDyedMap.end())
    {
        return formatString(it->second, colorName);
    }

    for (const std::string &potentialName : colorNames)
    {
        size_t dyeNamePos = currentName.find(potentialName);
        if (dyeNamePos == std::string::npos)
        {
            continue;
        }

        std::string prefix = currentName.substr(0, dyeNamePos);
        std::string suffix = currentName.substr(dyeNamePos + potentialName.size());
        std::string newBlockName = formatString("$+$+$+", prefix, colorName, suffix);

        if (newBlockName == currentName)
        {
            continue;
        }

        if (!blockRegistry.isValidBlock(newBlockName))
        {
            continue;
        }

        return newBlockName;
    }

    return currentName;
}

Dye::Dye(std::string name, std::string colorName, std::string displayName, Material &mat) :
    BasicItem(name, displayName, mat),
    colorName(colorName)
{}

void Dye::onUse(LocalWorld &world, IWorldActor &actor, ItemStack &stack, glm::ivec3 pos, Side side)
{
    Block *block = world.getBlockAt(pos);
    std::string newBlockName = getDyedBlockName(block->name);

    if (newBlockName == block->name)
    {
        return;
    }

    uint8_t meta = *world.getBlockMeta(pos);
    stack.extractOne();
    world.setBlockAt(pos, newBlockName, meta);
    world.playSound(Sound::paint, pos);
}