package net.halbear.aotg.custom.blocks.AlloyFurnace;

import io.netty.buffer.Unpooled;
import net.halbear.aotg.AgeoftheGods;
import net.halbear.aotg.registries.ModBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Connection;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.WorldlyContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.FuelValues;
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.neoforged.neoforge.transfer.ResourceHandler;
import net.neoforged.neoforge.transfer.StacksResourceHandler;
import net.neoforged.neoforge.transfer.item.ItemResource;
import net.neoforged.neoforge.transfer.item.ItemStacksResourceHandler;
import org.jspecify.annotations.Nullable;

import java.util.stream.IntStream;

import static net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceMultiBlock.*;
import static net.halbear.aotg.custom.blocks.AlloyFurnace.AlloyFurnaceUpdateHandler.getInverseRotationForDirection;
import static net.halbear.aotg.registries.ModBlockEntities.ALLOY_FURNACE_BLOCK_ENTITY;

public class AlloyFurnaceBlockEntity extends RandomizableContainerBlockEntity implements MenuProvider, WorldlyContainer {

    private boolean isFormed = false;
    private float Fuel = 0.0f;
    private float CookProcess = 0.0f;
    private float CurrentFuelTime = 0.0f;
    private float TemperatureC = 0.0f;
    private float BellowPush = 0.0f;
    private boolean AbleToCook = false;
    public static int MAX_BELLOW = 5;
    private boolean pushBellow = false;
    private boolean AbleToStartCooking;
    private NonNullList<ItemStack> items = NonNullList.withSize(8, ItemStack.EMPTY);

    public void PushBellow(){if(BellowPush < 1)pushBellow = true;}
    public int GetCookProgress(){return (int)CookProcess;}
    public void SetCookProgress(int CookProcess){this.CookProcess = CookProcess ;}
    public int GetBellowPush(){return (int)BellowPush;}
    public void SetBellowPush(int BellowPush){this.BellowPush = BellowPush ;}
    public int GetFuel(){return  (int)Fuel;}
    public void SetFuel(int Fuel){this.Fuel = Fuel ;}
    public int GetTemperatureC(){return (int) TemperatureC;}
    public void SetTemperatureC(int Temp){this.TemperatureC = Temp ;}
    public int GetCurrentFuelTime(){return (int) CurrentFuelTime;}
    public void SetCurrentFuelTime(int Temp){this.CurrentFuelTime = Temp ;}

    public AlloyFurnaceBlockEntity(BlockPos worldPosition, BlockState blockState) {
        super(ALLOY_FURNACE_BLOCK_ENTITY.get(), worldPosition, blockState);
    }

    public boolean UpdateCompleteStructure(Level level, BlockPos masterPos, BlockState blockState, boolean Complete){
        Direction direction = blockState.getValue(FACING);
        Rotation rotation =  getInverseRotationForDirection(direction);
        BlockPos[] Positions = new BlockPos[MULTI_BLOCK_POSITIONS.length + 1];
        Positions[0] = new BlockPos(0,0,0);
        for(int i = 0; i < MULTI_BLOCK_POSITIONS.length; i++){
            Positions[1 + i] = MULTI_BLOCK_POSITIONS[i];
        }
        for (BlockPos offset : Positions) {
            BlockPos Rotated = offset.rotate(rotation);
            BlockPos targetPos = masterPos.offset(Rotated);
            BlockState state = level.getBlockState(targetPos);
            if (state.getBlock().getName().getString().equals(ModBlocks.ALLOY_FURNACE.get().getName().getString())) {
                if (Complete) {
                    int Part = AlloyFurnaceUpdateHandler.GetModelPart(offset);
                    if (!state.getValue(COMPLETE_STRUCTURE)) state = state.setValue(COMPLETE_STRUCTURE, true);
                    if (state.getValue(PARENT_BLOCK) && !(offset.getX() == 0 && offset.getY() == 0 && offset.getZ() == 0)) state = state.setValue(AlloyFurnaceMultiBlock.PARENT_BLOCK, false);
                    if (state.getValue(MODEL_PART) != Part) state = state.setValue(AlloyFurnaceMultiBlock.MODEL_PART, Part);
                    if (state.getValue(FACING) != direction) state = state.setValue(FACING, direction);
                } else {
                    state = state.setValue(COMPLETE_STRUCTURE, false);
                }
                level.setBlockAndUpdate(targetPos, state);
            }
        }
        return Complete;
    }
    public static boolean checkStructure(Level level, BlockPos masterPos, BlockState blockState) {
        Direction direction = blockState.getValue(FACING);
        Rotation rotation =  getInverseRotationForDirection(direction);
        boolean Complete =true;
        for (BlockPos offset : MULTI_BLOCK_POSITIONS) {

            BlockPos Rotated = offset.rotate(rotation);
            BlockPos targetPos = masterPos.offset(Rotated);
            BlockState state = level.getBlockState(targetPos);

            if (!state.is(ModBlocks.ALLOY_FURNACE.get())) {
                Complete = false;
            }
        }

        return Complete;
    }


    public static void tick(Level level, BlockPos pos, BlockState state, AlloyFurnaceBlockEntity blockEntity) {
        if (level.isClientSide() || !state.getValue(AlloyFurnaceMultiBlock.PARENT_BLOCK)) return;
        if(blockEntity.pushBellow && blockEntity.BellowPush < MAX_BELLOW){
            blockEntity.BellowPush += 1;
        } else if(blockEntity.pushBellow) blockEntity.pushBellow = false;
        blockEntity.Fuel = Math.max(blockEntity.Fuel - 1f, 0);
        if (level.getGameTime() % 5 == 0) {
            if (level.getGameTime() % 20 == 0) {
                blockEntity.isFormed = blockEntity.UpdateCompleteStructure(level,pos,state,blockEntity.checkStructure(level, pos, state));
            }
            if (blockEntity.isFormed) {
                boolean AbleToStartCooking = blockEntity.items.get(2).getItem().equals(Items.DECORATED_POT) && (!blockEntity.items.get(0).isEmpty()||!blockEntity.items.get(1).isEmpty());
                blockEntity.BellowPush = Math.max(blockEntity.BellowPush - 1, 0);
                if(blockEntity.AbleToCook) {
                    if (blockEntity.Fuel > 0) {
                        if(AbleToStartCooking && blockEntity.CookProcess < 1 && blockEntity.items.get(5).isEmpty() && blockEntity.items.get(6).isEmpty() && blockEntity.items.get(7).isEmpty()){
                            blockEntity.items.set(5,blockEntity.items.get(0));
                            blockEntity.items.set(6,blockEntity.items.get(1));
                            blockEntity.items.set(7,blockEntity.items.get(2));
                            blockEntity.items.set(0,ItemStack.EMPTY);
                            blockEntity.items.set(1,ItemStack.EMPTY);
                            blockEntity.items.set(2,ItemStack.EMPTY);
                        }

                        if((!blockEntity.items.get(5).isEmpty() || !blockEntity.items.get(6).isEmpty() ) && !blockEntity.items.get(7).isEmpty()) {
                            blockEntity.CookProcess = Math.min(blockEntity.CookProcess + 1f + blockEntity.BellowPush,100);
                        } else blockEntity.CookProcess = 0;
                    } else if(!blockEntity.items.get(3).isEmpty() && ((!blockEntity.items.get(0).isEmpty() || !blockEntity.items.get(1).isEmpty() ) && !blockEntity.items.get(2).isEmpty() || (!blockEntity.items.get(5).isEmpty() || !blockEntity.items.get(6).isEmpty() ) && !blockEntity.items.get(7).isEmpty())){
                        blockEntity.Fuel = blockEntity.items.get(3).getBurnTime(RecipeType.SMELTING, level.fuelValues());
                        blockEntity.SetCurrentFuelTime((int)blockEntity.Fuel);
                        blockEntity.items.get(3).setCount(Math.max(blockEntity.items.get(3).getCount() - 1,0));
                    }
                    if (blockEntity.CookProcess >= 100f) {
                        if (blockEntity.items.get(4).isEmpty()&& ((!blockEntity.items.get(5).isEmpty() || !blockEntity.items.get(6).isEmpty() ) && !blockEntity.items.get(7).isEmpty())) {
                            blockEntity.items.set(4, AlloyFurnaceUpdateHandler.CreateFilledPot(blockEntity.items.get(5),blockEntity.items.get(6)));
                            blockEntity.items.set(5,ItemStack.EMPTY);
                            blockEntity.items.set(6,ItemStack.EMPTY);
                            blockEntity.items.set(7,ItemStack.EMPTY);
                        }
                        blockEntity.CookProcess = 0;
                    }
                } else{
                    blockEntity.CookProcess = 0f;
                }
                blockEntity.AbleToCook = blockEntity.items.get(4).isEmpty() ;
                blockEntity.AbleToStartCooking = blockEntity.items.get(2).getItem().equals(Items.DECORATED_POT) && (!blockEntity.items.get(0).isEmpty()||!blockEntity.items.get(1).isEmpty());
                blockEntity.setChanged();
            }
        }
    }

    @Override
    public void loadAdditional(ValueInput input) {
        super.loadAdditional(input);
        if (!this.tryLoadLootTable(input))
            this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY);
        ContainerHelper.loadAllItems(input, this.items);
        this.Fuel = input.getFloatOr("fuel",0);
        this.CookProcess = input.getFloatOr("cook_progress",0);
        this.TemperatureC = input.getFloatOr("temp",0);
        this.BellowPush = input.getFloatOr("bellow_push",0);
    }

    @Override
    public void saveAdditional(ValueOutput output) {
        super.saveAdditional(output);
        output.putFloat("fuel", this.Fuel);
        output.putFloat("cook_progress", this.CookProcess);
        output.putFloat("temp", this.TemperatureC);
        output.putFloat("bellow_push", this.BellowPush);
        if (!this.trySaveLootTable(output))
            ContainerHelper.saveAllItems(output, this.items);

    }

    @Override
    public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
        return this.saveWithFullMetadata(registries);
    }

    @Override
    public void handleUpdateTag(ValueInput input) {
        super.handleUpdateTag(input);
    }


    @Override
    public Packet<ClientGamePacketListener> getUpdatePacket() {
        return ClientboundBlockEntityDataPacket.create(this);
    }

    @Override
    public void onDataPacket(Connection connection, ValueInput input) {
        super.onDataPacket(connection, input);
    }

    @Override
    public Component getDisplayName() {
        return Component.translatable("container.ageofthegods.alloy_furnace");
    }

    @Override
    protected Component getDefaultName() {
        return null;
    }

    @Override
    public @Nullable AbstractContainerMenu createMenu(int i, Inventory inventory, Player player) {
        return new AlloyFurnaceGUI(i, inventory, new FriendlyByteBuf(Unpooled.buffer()).writeBlockPos(this.worldPosition));

    }

    @Override
    protected AbstractContainerMenu createMenu(int i, Inventory inventory) {
        return new AlloyFurnaceGUI(i, inventory, new FriendlyByteBuf(Unpooled.buffer()).writeBlockPos(this.worldPosition));
    }

    private final StacksResourceHandler<ItemStack, ItemResource> resourceHandler = new ItemStacksResourceHandler(this.items) {
        @Override
        protected void onContentsChanged(int index, ItemStack stack) {
            super.onContentsChanged(index, stack);
            setChanged();
        }
    };

    public StacksResourceHandler<ItemStack, ItemResource> getResourceHandler() {
        return this.resourceHandler;
    }


    @Override
    public int getContainerSize() {
        return items.size();
    }

    @Override
    public boolean isEmpty() {
        for (ItemStack itemstack : this.items)
            if (!itemstack.isEmpty())
                return false;
        return true;
    }

    @Override
    protected NonNullList<ItemStack> getItems() {
        return this.items;
    }

    @Override
    protected void setItems(NonNullList<ItemStack> stacks) {
        this.items = stacks;
    }

    @Override
    public boolean canPlaceItem(int index, ItemStack stack) {
        return true;
    }

    @Override
    public int[] getSlotsForFace(Direction side) {
        return IntStream.range(0, this.getContainerSize()).toArray();
    }

    @Override
    public boolean canPlaceItemThroughFace(int index, ItemStack itemstack, @Nullable Direction direction) {
        return this.canPlaceItem(index, itemstack);
    }

    @Override
    public boolean canTakeItemThroughFace(int index, ItemStack itemstack, Direction direction) {
        return true;
    }

    @Override
    public void clearContent() {
        items.clear();
    }
}
