package com.gregtechceu.gtceu.common.machine.multiblock.part;

import com.gregtechceu.gtceu.api.GTValues;
import com.gregtechceu.gtceu.api.blockentity.BlockEntityCreationInfo;
import com.gregtechceu.gtceu.api.capability.recipe.IO;
import com.gregtechceu.gtceu.api.machine.trait.notifiable.NotifiableFluidTank;
import com.gregtechceu.gtceu.api.transfer.fluid.CustomFluidTank;

import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.fluids.FluidStack;

import java.util.Collections;

import javax.annotation.ParametersAreNonnullByDefault;

@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class ReservoirHatchPartMachine extends FluidHatchPartMachine {

    protected InfiniteWaterTank waterTank;

    public static final int FLUID_AMOUNT = 2_000_000_000;

    public ReservoirHatchPartMachine(BlockEntityCreationInfo info) {
        super(info, GTValues.EV, IO.IN, new NotifiableFluidTank(
                Collections.singletonList(new InfiniteWaterTank(FLUID_AMOUNT)), IO.IN, IO.BOTH));
        waterTank = (InfiniteWaterTank) tank.getStorages()[0];
    }

    //////////////////////////////////
    // ******** Fill Water ******** //
    //////////////////////////////////

    @Override
    protected void updateTankSubscription() {
        if (isWorkingEnabled() && !waterTank.isFull()) {
            autoIOSubs = subscribeServerTick(autoIOSubs, this::autoIO);
        } else if (autoIOSubs != null) {
            autoIOSubs.unsubscribe();
            autoIOSubs = null;
        }
    }

    @Override
    protected void autoIO() {
        // replace with refilling water tank
        if (getOffsetTimer() % 20 == 0) {
            waterTank.refillWater();
            updateTankSubscription();
        }
    }

    // By returning false here, we don't allow shift-clicking
    // with a screwdriver to swap the IO.
    @Override
    public boolean swapIO() {
        return false;
    }

    protected static class InfiniteWaterTank extends CustomFluidTank {

        private static final CompoundTag EMPTY = new CompoundTag();
        private static final FluidStack WATER = new FluidStack(Fluids.WATER, Integer.MAX_VALUE);

        public InfiniteWaterTank(int capacity) {
            super(capacity);
            // start with the full amount
            setFluid(new FluidStack(Fluids.WATER, capacity));
        }

        public void refillWater() {
            // call super since our overrides don't allow any kind of filling
            super.fill(WATER, FluidAction.EXECUTE);
        }

        public boolean isFull() {
            return getFluidAmount() >= capacity;
        }

        @Override
        public boolean supportsFill(int tank) {
            // don't allow external callers to fill this tank
            return false;
        }

        @Override
        public int fill(FluidStack resource, FluidAction action) {
            // don't allow external filling
            return 0;
        }

        @Override
        public CompoundTag serializeNBT() {
            // serialization is unnecessary here, we can always recreate it completely full since it would refill anyway
            return EMPTY;
        }

        @Override
        public void deserializeNBT(CompoundTag nbt) {}
    }
}
