#include <Block/SpriteBlock/ItemExtractor/ItemExtractor.hpp>
#include <World/LocalWorld/LocalWorld.hpp>
#include <Controller/InventoryController/ItemExtractorController/ItemExtractorController.hpp>

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

    for (uint8_t meta = 0; meta < numStates; meta++)
    {
        Side outputSide = getMetaOutputSide(meta);

        Sprite sprite = {
            {
                "itemExtractor/side",
                "itemExtractor/side",
                "itemExtractor/side",
                "itemExtractor/side",
                "itemExtractor/electricInput",
                "itemExtractor/data"
            },
            {{0, 0, 0, 8, 8, 8}},
            formatString("output$+", outputSide),
        };

        sprite.texturesOnSides[outputSide.asNumber()] = "itemExtractor/output";
        sprites.push_back(sprite);
    }

    return sprites;
}

ItemExtractor::ItemExtractor(std::string name) : SpriteBlock(
    name,
    "Item Extractor",
    60.0f,
    "itemExtractor/side",
    makeSprites()
)
{
    withMetalSounds();
}

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

Sound& ItemExtractor::getBackgroundSound(uint8_t meta)
{
    if (meta & metaActive)
    {
        return Sound::motor;
    }

    return Sound::NONE;
}

bool ItemExtractor::canPlace(LocalWorld &world, IWorldActor &actor, glm::ivec3 pos, Side side, uint8_t &meta)
{
    if (side.isZ())
    {
        return false;
    }

    if (world.getBlockAt(pos + side.out())->isSuffixed("Casing"))
    {
        meta = side.opposite().asNumber();
        return true;
    }

    std::shared_ptr<IBeltMachine> machine = std::dynamic_pointer_cast<IBeltMachine>(world.getMachine(pos + side.out()));
    if (machine == nullptr)
    {
        return false;
    }

    Side outputSide = side.opposite();
    if (!machine->canConnectExtractor(outputSide))
    {
        return false;
    }

    meta = outputSide.asNumber();
    return true;
}

void ItemExtractor::onInteract(LocalWorld &world, Player &player, glm::ivec3 pos, Side side, const RGBABytes &collisionKey)
{
    player.connectController<ItemExtractorController>(
        "main:ItemExtractorController",
        world.getMachine(pos)
    );
}