#include <Block/SpriteBlock/Accumulator/Accumulator.hpp>
#include <Milestone/ElectronicsMilestone/ElectronicsMilestone.hpp>
#include <World/LocalWorld/LocalWorld.hpp>
#include <Entity/PhysicsEntity/CameraEntity/Player/Player.hpp>
#include <Controller/InventoryController/AccumulatorController/AccumulatorController.hpp>

std::vector<Accumulator::Sprite> Accumulator::makeSprites()
{
    std::vector<Sprite> sprites;

    for (const Side &side : Side::all)
    {
        Sprite sprite{
            {
                "accumulator/output",
                "accumulator/output",
                "accumulator/output",
                "accumulator/output",
                "accumulator/output",
                "accumulator/output",
            },
            {
                BoundingBox<int>{0, 0, 0, 8, 8, 8},
            },
            formatString("input$+", side.name())
        };

        sprite.texturesOnSides[side.asNumber()] = "accumulator/input";
        sprites.push_back(sprite);
    }

    return sprites;
}

Accumulator::Accumulator(std::string name) :
    SpriteBlock(
        name,
        "Accumulator",
        30.0f,
        "accumulatorOutput",
        makeSprites()
    )
{
    withMetalSounds();
}

bool Accumulator::canManuallyDig()
{
    return true;
}

void Accumulator::onInteract(LocalWorld &world, Player &player, glm::ivec3 pos, Side side, const RGBABytes &collisionKey)
{
    if (player.isHoldingScrewdriver())
    {
        uint8_t meta = *world.getBlockMeta(pos);
        world.setBlockMeta(pos, (meta + 1) % 6, true);

        return;
    }

    player.achieve(ElectronicsMilestone::ID, ElectronicsMilestone::MakeAccumulator);
    player.connectController<AccumulatorController>(
        "main:AccumulatorController",
        world.getMachine(pos)
    );
}

void Accumulator::getHarvestedStacks(LocalWorld &world, glm::ivec3 pos, std::vector<ItemStack> &stacks)
{
    SpriteBlock::getHarvestedStacks(world, pos, stacks);
 
    std::shared_ptr<IInventory> inv = std::dynamic_pointer_cast<IInventory>(world.getMachine(pos));
    if (inv != nullptr)
    {
        int i;
        for (i=0; i<inv->getNumSlots(); i++)
        {
            ItemStack stack = inv->getStackInSlot(i);
            if (!stack.isEmpty())
            {
                stacks.push_back(stack);
            }
        }
    }
}

bool Accumulator::canPlace(LocalWorld &world, IWorldActor &actor, glm::ivec3 pos, Side side, uint8_t &meta)
{
    meta = actor.getSideFacing2D().opposite().asNumber();
    return true;
}
