#include <AssetManager/AssetManager.hpp>
#include <BlockSprite/BlockSprite.hpp>
#include <TextureVoxelizer/TextureVoxelizer.hpp>
#include <Utilities/Utilities.hpp>
#include <VoxelSprite/VoxelSprite.hpp>

TextureVoxelizer::Texture::Texture(const std::string &name) :
    colorMap(Bitmap::fromFileOrDefault(assets.resolve(formatString("blocktex/$+.png", name)))),
    lightMap(Bitmap::fromFile(assets.resolve(formatString("blocklm/$+.png", name)))),
    biasMap(Bitmap::fromFile(assets.resolve(formatString("blockbias/$+.png", name)))),
    specularMap(Bitmap::fromFile(assets.resolve(formatString("blockspecular/$+.png", name)))),
    refractMap(Bitmap::fromFile(assets.resolve(formatString("blockrefract/$+.png", name))))
{}

void TextureVoxelizer::makeVoxel(BlockSprite &sprite, size_t frameNum, glm::ivec3 offset, Texture &tex, glm::uvec2 texPos)
{
    BlockSprite::Frame &frame = sprite.frames[frameNum];
    texPos.y += (frameNum * 8) % tex.colorMap.getSize().y;

    frame.colorMap.at(offset) = tex.colorMap.getColor(texPos);
    if (tex.lightMap.has_value())
    {
        frame.lightSpecMap.at(offset) = tex.lightMap->getColor(texPos);
        frame.lightSpecMap.at(offset).alpha = 0;
    }

    if (tex.biasMap.has_value())
    {
        frame.biasMap.at(offset) = tex.biasMap->getColor(texPos);
    }

    if (tex.specularMap.has_value())
    {
        frame.lightSpecMap.at(offset).alpha = tex.specularMap->getColor(texPos).green;
    }

    if (tex.refractMap.has_value())
    {
        frame.refractMap.at(offset) = tex.refractMap->getColor(texPos);
    }
}

TextureVoxelizer::TextureVoxelizer(std::array<std::string, 6> sideTextureNames) :
    sideTextures{
        Texture(sideTextureNames[0]),
        Texture(sideTextureNames[1]),
        Texture(sideTextureNames[2]),
        Texture(sideTextureNames[3]),
        Texture(sideTextureNames[4]),
        Texture(sideTextureNames[5]),
    }
{}

void TextureVoxelizer::makeBox(BlockSprite &sprite, BoundingBox<int> box)
{
    size_t framesNeeded = sprite.frames.size();
    for (Texture &tex : sideTextures)
    {
        size_t texFrames = tex.colorMap.getSize().y / 8;
        if (texFrames > framesNeeded)
        {
            framesNeeded = texFrames;
        }
    }

    while (sprite.frames.size() < framesNeeded)
    {
        sprite.addFrame();
    }

    for (size_t frameNum = 0; frameNum < framesNeeded; frameNum++)
    {
        glm::ivec3 offset;
        for (offset.z = box.z0; offset.z < box.z1; offset.z++)
        {
            for (offset.y = box.y0; offset.y < box.y1; offset.y++)
            {
                for (offset.x = box.x0; offset.x < box.x1; offset.x++)
                {
                    if (offset.x == box.x0)
                    {
                        makeVoxel(sprite, frameNum, offset, sideTextures[0], glm::uvec2(7 - offset.y, 7 - offset.z));
                    }
                    else if (offset.x == box.x1 - 1)
                    {
                        makeVoxel(sprite, frameNum, offset, sideTextures[1], glm::uvec2(offset.y, 7 - offset.z));
                    }
                    else if (offset.y == box.y0)
                    {
                        makeVoxel(sprite, frameNum, offset, sideTextures[2], glm::uvec2(offset.x, 7 - offset.z));
                    }
                    else if (offset.y == box.y1 - 1)
                    {
                        makeVoxel(sprite, frameNum, offset, sideTextures[3], glm::uvec2(7 - offset.x, 7 - offset.z));
                    }
                    else if (offset.z == box.z1 - 1)
                    {
                        makeVoxel(sprite, frameNum, offset, sideTextures[5], glm::uvec2(offset.x, 7 - offset.y));
                    }
                    else if (offset.z == box.z0)
                    {
                        makeVoxel(sprite, frameNum, offset, sideTextures[4], glm::uvec2(offset.x, offset.y));
                    }
                    else
                    {
                        makeVoxel(sprite, frameNum, offset, sideTextures[5], glm::uvec2(offset.x, 7 - offset.y));
                    }
                }
            }
        }
    }
}