#include <FluidRegistry/FluidRegistry.hpp>
#include <Item/StatefulItem/FissionCell/FissionCell.hpp>
#include <Machine/MNuclearReactor/MNuclearReactor.hpp>
#include <Controller/InventoryController/NuclearReactorController/NuclearReactorController.hpp>

FissionCell::FissionCell(
    std::string name,
    std::string displayName,
    Material &icon,
    std::string fuelFluidName,
    int powerOutput,
    int maxDamage
) : StatefulItem(name),
    displayName(displayName),
    icon(icon),
    fuelFluidName(fuelFluidName),
    powerOutput(powerOutput),
    maxDamage(maxDamage)
{
    setMaxStackSize(1);
}

void FissionCell::describeInNuclearReactor(ItemStack &stack, std::ostream &os)
{
    Fluid *fuel = fluidRegistry.getFluidByName(fuelFluidName);

    os << "Pumps in 1 " << fuel->displayName << " per tick." << std::endl;
    os << "Outputs " << powerOutput << " J/t." << std::endl;
    os << "Generates heat." << std::endl;
}

bool FissionCell::updateNuclearReactor(ItemStack &stack, MNuclearReactor &reactor, glm::ivec2 cellPos)
{
    if (!reactor.tryConsumeFluid(fuelFluidName, 1))
    {
        return false;
    }

    reactor.generateEnergy(powerOutput);
    reactor.heatCell(cellPos, 2100);
    reactor.uraniumBurned++;

    return true;
}

void FissionCell::onOverheating(ItemStack &stack, MNuclearReactor &reactor, glm::ivec2 cellPos)
{
    reactor.meltdown();

    if (++state(stack) == maxDamage)
    {
        reactor.explode();
    }
}

glm::vec4 FissionCell::getNuclearReactorSlotHighlight(ItemStack &stack, NuclearReactorController &ctrl, glm::ivec2 cellPos)
{
    if (ctrl.getCellTemperature(cellPos) >= MNuclearReactor::criticalTemperature)
    {
        return Color::warning;
    }

    return glm::vec4(0.0f);
}

float FissionCell::getHeatConductivity(ItemStack &stack)
{
    return 0.3f;
}

std::string FissionCell::getDisplayName(const ItemStack &stack)
{
    return displayName;
}

void FissionCell::draw(GraphicsContext &context, int x, int y, const ItemStack &stack)
{
    context.color = glm::vec4(1.0f);
    context.drawMaterial(icon, x, y);

    uint32_t usesLeft = maxDamage - state(stack);
    if (usesLeft == maxDamage)
    {
        return;
    }

    context.color = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
    context.drawRect(x, y+6, 8, 2);

    context.color = Color::warning;
    context.drawRect(x, y+6, 8 * usesLeft / maxDamage, 2);
}

void FissionCell::draw3D(GraphicsContext &context, WorldDisplay &worldDisplay, glm::vec3 pos, ItemStack &stack)
{
    worldDisplay.drawMeshedIcon(context, icon, pos);
}

void FissionCell::drawFlat(GraphicsContext &context, WorldDisplay &worldDisplay, glm::mat4 matrix, ItemStack &stack)
{
    worldDisplay.drawMeshedIconFlat(context, icon, matrix);
}