package com.acethewildfire.acesbs.block.entity.custom;

import com.acethewildfire.acesbs.block.custom.EntropicEntangler;
import com.acethewildfire.acesbs.block.entity.EntanglerInventory;
import com.acethewildfire.acesbs.block.entity.ModBlockEntities;
import com.acethewildfire.acesbs.recipe.EntropicEntanglerRecipe;
import com.acethewildfire.acesbs.recipe.EntropicEntanglerRecipeInput;
import com.acethewildfire.acesbs.recipe.ModRecipies;
import com.acethewildfire.acesbs.screen.custom.EntropicEntanglerScreenHandler;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.Inventories;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.listener.ClientPlayPacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
import net.minecraft.recipe.RecipeEntry;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.screen.PropertyDelegate;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;

import java.util.Optional;

public class EntropicEntanglerEntity extends BlockEntity implements EntanglerInventory, ExtendedScreenHandlerFactory<BlockPos> {
    private final DefaultedList<ItemStack> inventory = DefaultedList.ofSize(3, ItemStack.EMPTY);
    private Direction facing;

    private static final int INPUT_SLOT = 0;
    private static final int INPUT2_SLOT = 1;
    private static final int OUTPUT_SLOT = 2;

//    private static final int FUEL_PROGRESS = 0;
//    private static final int FUEL_MAX_PROGRESS = 1;
    private static final int ENTANGLE_PROGRESS = 2;
    private static final int ENTANGLE_MAX_PROGRESS = 3;

//    private int fuel_progress = -1;
//    private int fuel_max_progress = 400;
    private int entangle_progress = 0;
    private int entangle_max_progress = 200;

    protected final PropertyDelegate propertyDelegate;

    public EntropicEntanglerEntity(BlockPos pos, BlockState state) {
        super(ModBlockEntities.E_ENTANGLER_BE, pos, state);
        this.facing = state.get(EntropicEntangler.FACING);
        this.propertyDelegate = new PropertyDelegate() {
            @Override
            public int get(int index) {
                return switch (index) {
//                    case 0 -> EntropicEntanglerEntity.this.fuel_progress;
//                    case 1 -> EntropicEntanglerEntity.this.fuel_max_progress;
                    case 2 -> EntropicEntanglerEntity.this.entangle_progress;
                    case 3 -> EntropicEntanglerEntity.this.entangle_max_progress;
                    default -> 0;
                };
            }

            @Override
            public void set(int index, int value) {
                switch (index) {
//                    case 0 -> EntropicEntanglerEntity.this.fuel_progress = value;
//                    case 1 -> EntropicEntanglerEntity.this.fuel_max_progress = value;
                    case 2 -> EntropicEntanglerEntity.this.entangle_progress = value;
                    case 3 -> EntropicEntanglerEntity.this.entangle_max_progress = value;
                }
            }

            @Override
            public int size() {
                return 4;
            }
        };
    }

    public Direction getFacing() {
        return facing;
    }

    public void setFacing(Direction newFacing) {
        this.facing = newFacing;
        // sync to blockstate for rendering
        if (world != null && !world.isClient) {
            world.setBlockState(pos, getCachedState().with(EntropicEntangler.FACING, newFacing), 3);
            markDirty();
        }
    }

    @Override
    protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
        super.writeNbt(nbt, registryLookup);
        Inventories.writeNbt(nbt, inventory, registryLookup);
        nbt.putInt("Facing", facing.getId());
//        nbt.putInt("entangler.fuel_progress", fuel_progress);
//        nbt.putInt("entangler.fuel_max_progress", fuel_max_progress);
        nbt.putInt("entangler.entangle_progress", entangle_progress);
        nbt.putInt("entangler.entangle_max_progress", entangle_max_progress);
    }

    @Override
    protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
        Inventories.readNbt(nbt, inventory, registryLookup);
        this.facing = Direction.byId(nbt.getInt("Facing"));
//        this.fuel_progress = nbt.getInt("entangler.fuel_progress");
//        this.fuel_max_progress = nbt.getInt("entangler.fuel_max_progress");
        this.entangle_progress = nbt.getInt("entangler.entangle_progress");
        this.entangle_max_progress = nbt.getInt("entangler.entangle_max_progress");
        super.readNbt(nbt, registryLookup);
    }

    @Override
    public DefaultedList<ItemStack> getItems() {
        return inventory;
    }

    @Override
    public BlockPos getScreenOpeningData(ServerPlayerEntity serverPlayerEntity) {
        return this.pos;
    }

    @Override
    public Text getDisplayName() {
        return Text.translatable("block.acesbs.entropic_entangler");
    }

    @Override
    public @Nullable ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) {
        return new EntropicEntanglerScreenHandler(syncId, playerInventory, this, propertyDelegate);
    }

    public float getCookProgress() {
        int i = this.propertyDelegate.get(ENTANGLE_PROGRESS);
        int j = this.propertyDelegate.get(ENTANGLE_MAX_PROGRESS);
        return j != 0 && i != 0 ? MathHelper.clamp((float)i / (float)j, 0.0F, 1.0F) : 0.0F;
    }

//    public float getFuelProgress() {
//        int i = this.propertyDelegate.get(FUEL_MAX_PROGRESS);
//        if (i == 0) {
//            i = 200;
//        }
//
//        return MathHelper.clamp((float)this.propertyDelegate.get(FUEL_PROGRESS) / (float) i, 0.0F, 1.0F);
//    }

//    public boolean canInsertIntoSlot(int index) {
//        return index != 1;
//    }

    public void tick(World world, BlockPos pos, BlockState state) {
        if(hasRecipe()) {
            increaseCraftingProgress();
            markDirty(world, pos, state);

            if(hasCraftingFinished()) {
                craftItem();
                resetProgress();
            }
        } else {
            resetProgress();
        }
    }

//    private boolean hasFuel() {
//        return this.getStack(INPUT2_SLOT).isOf(ModItems.STABLE_ENTROPY);
//    }

//    private boolean hasUnfinishedFuel() {
//        return this.fuel_progress > -1 && !hasFuelFinished();
//    }

    private void resetProgress() {
        this.entangle_progress = 0;
        this.entangle_max_progress = 200;
    }

//    private void resetFuelProgress() {
//        this.fuel_progress = 0;
//        this.fuel_max_progress = 400;
//    }

    private void craftItem() {
        Optional<RecipeEntry<EntropicEntanglerRecipe>> recipe = getCurrentRecipe();
        ItemStack output = recipe.get().value().output();

        this.removeStack(INPUT_SLOT, 1);
        this.removeStack(INPUT2_SLOT, 1);
        this.setStack(OUTPUT_SLOT, new ItemStack(output.getItem(),
                this.getStack(OUTPUT_SLOT).getCount() + output.getCount()));
    }

    private void consumeFuel() {
        this.setStack(INPUT2_SLOT, new ItemStack(this.getStack(INPUT2_SLOT).getItem(),
                this.getStack(INPUT2_SLOT).getCount() - 1));
    }

    private boolean hasCraftingFinished() {
        return this.entangle_progress >= this.entangle_max_progress;
    }

//    private boolean hasFuelFinished() {
//        return this.fuel_progress >= this.fuel_max_progress;
//    }

    private void increaseCraftingProgress() {
        this.entangle_progress++;
//        this.fuel_progress++;
    }

    private boolean hasRecipe() {
        Optional<RecipeEntry<EntropicEntanglerRecipe>> recipe = getCurrentRecipe();

        if (recipe.isEmpty()){ return false; }

        ItemStack output = recipe.get().value().output();

        return canInsertAmountIntoOutputSlot(output.getCount()) && canInsertItemIntoOutputSlot(output);
    }

    private Optional<RecipeEntry<EntropicEntanglerRecipe>> getCurrentRecipe() {
        return this.getWorld().getRecipeManager()
                .getFirstMatch(ModRecipies.ENTROPIC_ENTANGLER_TYPE, new EntropicEntanglerRecipeInput(inventory.get(INPUT_SLOT), inventory.get(INPUT2_SLOT)), this.getWorld());
    }

    private boolean canInsertItemIntoOutputSlot(ItemStack output) {
        return this.getStack(OUTPUT_SLOT).isEmpty() || this.getStack(OUTPUT_SLOT).getItem() == output.getItem();
    }

    private boolean canInsertAmountIntoOutputSlot(int count) {
        int maxCount = this.getStack(OUTPUT_SLOT).isEmpty() ? 64 : this.getStack(OUTPUT_SLOT).getMaxCount();
        int currentCount = this.getStack(OUTPUT_SLOT).getCount();

        return maxCount >= currentCount + count;
    }

    @Nullable
    @Override
    public Packet<ClientPlayPacketListener> toUpdatePacket() {
        return BlockEntityUpdateS2CPacket.create(this);
    }

    @Override
    public NbtCompound toInitialChunkDataNbt(RegistryWrapper.WrapperLookup registryLookup) {
        return createNbt(registryLookup);
    }


}
