#include "BlockInfoCommand.h"

#include <Logging.h>

#include "Block.h"
#include "BlockType.h"
#include "Chat.h"
#include "Dimension.h"
#include "Game.h"

BlockInfoCommand::BlockInfoCommand()
    : ChatCommand("block_info", "Outputs information of a specified block", 1)
{
    addParam(
        new IntegerParameter("x", "The x position of the block", false, 0));
    addParam(
        new IntegerParameter("y", "The y position of the block", false, 0));
    addParam(
        new IntegerParameter("z", "The z position of the block", false, 0));
    addParam(new IntegerParameter(
        "dimensionId", "The dimensionId of the block", true, [](Entity* e) {
            if (e) return e->getDimensionId();
            return 0;
        }));
}

bool BlockInfoCommand::execute(
    Framework::RCArray<Framework::Text>& params, Entity* zActor) const
{
    int x = (int)*params.z(0);
    int y = (int)*params.z(1);
    int z = (int)*params.z(2);
    int dimension = (int)*params.z(3);
    Framework::Vec3<int> location = {x, y, z};
    Framework::Text result = "";
    bool ok = 1;
    if (Game::INSTANCE->zDimension(dimension))
    {
        auto block = Game::INSTANCE->zBlockAt(location, dimension, 0);

        if (block.isB())
        {
            result += "No block instance was created yet.\n";
            result += "  Block Type: ";
            if (block.getB() == 0)
            {
                result += "[not loaded]";
            }
            else
            {
                result += Game::INSTANCE->zBlockType(block.getB())->getName();
            }
            result += " (";
            result += block.getB();
            result += ")\n";
        }
        else
        {
            Block* zBlock = block.getA();
            result.append()
                << "Block instance found.\n"
                << "  Block Type: " << zBlock->zBlockType()->getName() << " ("
                << zBlock->zBlockType()->getId() << ")\n"
                << "  HP: " << zBlock->getHP() << " / " << zBlock->getMaxHP()
                << "\n"
                << "  Transparent: " << zBlock->isTransparent() << "\n"
                << "  Passable: " << zBlock->isPassable() << "\n"
                << "  Hardness: " << zBlock->getHardness() << "\n"
                << "  Tick source: " << zBlock->isTickSource() << "\n"
                << "  Interactable by hand: " << zBlock->isInteractable(0)
                << "\n"
                << "  Light emission: ("
                << (int)zBlock->getLightEmisionColor()[0] << ", "
                << (int)zBlock->getLightEmisionColor()[1] << ", "
                << (int)zBlock->getLightEmisionColor()[2] << ")\n";
        }
        result += "  Light data: ";
        Chunk* zChunk = Game::INSTANCE->zDimension(dimension)->zChunk(
            Game::getChunkCenter(x, y));
        if (zChunk)
        {
            unsigned char* light
                = zChunk->getLightData(Dimension::chunkCoordinates(location));
            result.append()
                << "(" << (int)light[0] << ", " << (int)light[1] << ", "
                << (int)light[2] << ", " << (int)light[3] << ", "
                << (int)light[4] << ", " << (int)light[5] << ")";
        }
        else
        {
            result += "[not loaded]";
        }
        result += "\n";
        for (int i = 0; i < 6; i++)
        {
            Framework::Vec3<int> pos
                = location + getDirection(getDirectionFromIndex(i));
            if (pos.z >= 0 && pos.z < WORLD_HEIGHT)
            {
                switch (i)
                {
                case 0:
                    result += "    North: ";
                    break;
                case 1:
                    result += "    East: ";
                    break;
                case 2:
                    result += "    South: ";
                    break;
                case 3:
                    result += "    West: ";
                    break;
                case 4:
                    result += "    Top: ";
                    break;
                case 5:
                    result += "    Bottom: ";
                    break;
                }
                zChunk = Game::INSTANCE->zDimension(dimension)->zChunk(
                    Game::getChunkCenter(x, y));
                if (zChunk)
                {
                    unsigned char* light = zChunk->getLightData(
                        Dimension::chunkCoordinates(pos));
                    result.append()
                        << "(" << (int)light[0] << ", " << (int)light[1] << ", "
                        << (int)light[2] << ", " << (int)light[3] << ", "
                        << (int)light[4] << ", " << (int)light[5] << ")";
                }
                else
                {
                    result += "[not loaded]";
                }
                result += "\n";
            }
        }
    }
    else
    {
        result += "Given dimension is not loaded";
        ok = 0;
    }
    if (zActor)
    {
        Game::INSTANCE->zChat()->sendMessageTo(
            result, zActor, Chat::CHANNEL_INFO);
    }
    else
    {
        Framework::Logging::info() << result;
    }
    return ok;
}