#include <Block/SpriteBlock/Barrel/Barrel.hpp>
#include <BlockRegistry/BlockRegistry.hpp>
#include <Controller/InventoryController/BarrelController/BarrelController.hpp>
#include <Widget/Label/Label.hpp>
#include <Widget/Layout/CompoundWidget/IconText/IconText.hpp>
#include <Widget/StaticItemSlot/ItemSlot/ItemSlot.hpp>
#include <Widget/Layout/Row/Row.hpp>
#include <Widget/Layout/Column/Column.hpp>
#include <Widget/Layout/Center/Center.hpp>
#include <Widget/Builder/Builder.hpp>
#include <Utilities/Utilities.hpp>
#include <Entity/PhysicsEntity/CameraEntity/Player/Player.hpp>
#include <World/World.hpp>
#include <Widget/FlameStatusIndicator/FlameStatusIndicator.hpp>
#include <Widget/FluidLevelIndicator/FluidLevelIndicator.hpp>
#include <Widget/Panel/Panel.hpp>
#include <World/World.hpp>
#include <FluidRegistry/FluidRegistry.hpp>
#include <Widget/DownArrow/DownArrow.hpp>
#include <optional>

Widget* BarrelController::getCaption()
{
    if (!tier.has_value())
    {
        return new Label("Barrel");
    }

    switch (*tier)
    {
        case BarrelTier::Wooden: return new IconText(
            blockRegistry.getBlockByName("main:woodenBarrel").iconMaterial,
            "Wooden Barrel"
        );
        case BarrelTier::Steel: return new IconText(
            blockRegistry.getBlockByName("main:steelBarrel").iconMaterial,
            "Steel Barrel"
        );
        case BarrelTier::Lead: return new IconText(
            blockRegistry.getBlockByName("main:leadBarrel").iconMaterial,
            "Lead Barrel"
        );
        default: return new IconText(Material::alert, "Invalid Barrel Tier");
    }
}

BarrelController::BarrelController(ControllerChannel &channel) :
    InventoryController(channel),
    initBarrelTier(this, RunsOn::Client,
        [this](BarrelTier tier) -> uint32_t
    {
        this->tier = tier;
        return 0;
    }),
    updateBarrelState(this, RunsOn::Client,
        [this](std::string fluidName, int fluidAmount) -> uint32_t
    {
        this->fluidName = fluidName;
        this->fluidAmount = fluidAmount;

        return 0;
    })
{}

void BarrelController::onConnect(std::shared_ptr<Machine> barrelMachine)
{
    bindMachine(barrelMachine);
    barrel = std::dynamic_pointer_cast<MBarrel>(barrelMachine);
}

Widget* BarrelController::getRightPanel()
{
    return new Column(
        new Center(new Builder<std::optional<BarrelTier>>(
            tier,
            [this](std::optional<BarrelTier>)
            {
                return getCaption();
            }
        )),

        Layout::WithProportion<1>(),
        new Center(
            new Column(
                new Center(new ItemSlot(this, "machine", 0)),
                new Center(new DownArrow()),
                new Center(new FluidLevelIndicator(fluidName, fluidAmount, MBarrel::capacity)),
                new Center(new DownArrow()),
                new Center(new ItemSlot(this, "machine", 1))
            )
        )
    );
}

void BarrelController::update()
{
    InventoryController::update();

    if (world.isLocal() && barrel != nullptr)
    {
        if (!tier.has_value())
        {
            BarrelTier barrelTier = static_cast<Barrel&>(barrel->m_world.getBlockById(barrel->blockId)).tier;
            tier = barrelTier;
            initBarrelTier(barrelTier);
        }

        if (fluidName != barrel->getFluidName() || fluidAmount != barrel->getFluidAmount())
        {
            fluidName = barrel->getFluidName();
            fluidAmount = barrel->getFluidAmount();
            
            updateBarrelState(barrel->getFluidName(), barrel->getFluidAmount());
        }
    }
}