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.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Containers;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleMenuProvider;
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.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.BlockHitResult;
import org.jspecify.annotations.Nullable;

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

public class AlloyFurnaceMultiBlock extends Block implements EntityBlock {

    public static final BlockPos[] MULTI_BLOCK_POSITIONS = {
            /*Master block is 0,0,0*/      new BlockPos(0,0,1),
            new BlockPos(-1,0,0), new BlockPos(-1,0,1),
            new BlockPos(0,1,0), new BlockPos(-1,1,0),
            new BlockPos(-1,1,1), new BlockPos(0,1,1)
    };

    public static final EnumProperty<Direction> FACING = BlockStateProperties.HORIZONTAL_FACING;
    public static final IntegerProperty MODEL_PART = IntegerProperty.create("modelpart",0,8);
    public static final BooleanProperty PARENT_BLOCK = BooleanProperty.create("parent");
    public static final BooleanProperty COMPLETE_STRUCTURE = BooleanProperty.create("complete_structure");

    public AlloyFurnaceMultiBlock(Properties properties) {
        super(properties);
        this.registerDefaultState(this.defaultBlockState().setValue(MODEL_PART,0).setValue(COMPLETE_STRUCTURE,false).setValue(PARENT_BLOCK,true).setValue(FACING,Direction.NORTH));
    }

    @Override
    protected void affectNeighborsAfterRemoval(BlockState state, ServerLevel level, BlockPos pos, boolean movedByPiston) {
        Containers.updateNeighboursAfterDestroy(state, level, pos);
    }

    private static <E extends BlockEntity, A extends BlockEntity> @javax.annotation.Nullable BlockEntityTicker<A> createTickerHelper(
            BlockEntityType<A> type, BlockEntityType<E> checkedType, BlockEntityTicker<? super E> ticker
    ) {
        return checkedType == type ? (BlockEntityTicker<A>) ticker : null;
    }

    @Override
    public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
        return createTickerHelper(type, ALLOY_FURNACE_BLOCK_ENTITY.get(), AlloyFurnaceBlockEntity::tick);
    }


    @Override
    public BlockState getStateForPlacement(BlockPlaceContext context) {
        BlockState blockState = this.defaultBlockState();
        BlockPos position = context.getClickedPos();
        Level level = context.getLevel();
        blockState = blockState.setValue(FACING, context.getHorizontalDirection().getOpposite());

        for(int x = -1; x < 2; x++){
            for(int z = -1; z < 2; z++){
                for(int y = -1; y < 2; y++){
                    if(x == 0 && y == 0 && z == 0) continue; //skip if it is the block we're checking to place
                    /*check 3x3x3 area
                    and assign a BlockPos, and BlockState to the block at each offset*/
                    BlockPos parentPos = position.offset(x,y,z);
                    BlockState state = level.getBlockState(parentPos);

                    if(state.is(ModBlocks.ALLOY_FURNACE.get()) && state.getValue(PARENT_BLOCK)) {
                        //make sure the block matches, and that it has the "PARENT_BLOCK" boolean set to true, this means it is the parent block
                        Direction direction = state.getValue(FACING);
                        //get direction of parent block and then flip it to get the rotation
                        Rotation rotation =  getInverseRotationForDirection(direction);
                        for (BlockPos offset : MULTI_BLOCK_POSITIONS) {
                        //iterate through the child block positions
                            BlockPos Rotated = offset.rotate(rotation);
                            //rotate the child block position to face the direction of the parent block
                            BlockPos targetPos = parentPos.offset(Rotated);
                            //get the World Position of the child block and check if it matches the block we want to place
                            if (targetPos.getX() == position.getX() && targetPos.getY() == position.getY() && targetPos.getZ() == position.getZ()) {
                                //if it matches, the block we're placing is a child block, so set its parent value to false and its direction to the parent
                                blockState = blockState.setValue(PARENT_BLOCK, false);
                                blockState = blockState.setValue(FACING, direction);
                                //get an absolute value of the original child offset before rotating it
                                BlockPos purePos = new BlockPos(Math.abs(offset.getX()) , Math.abs(offset.getY()),Math.abs(offset.getZ()));
                                //set the model part to whatever value gets cross-matched when looking up offset positions in a Map containing the position and the respective model value
                                blockState = blockState.setValue(MODEL_PART, Math.max(AlloyFurnaceUpdateHandler.GetModelPart(purePos), 0));
                                return blockState;
                            }
                        }
                    }
                }
            }
        }

        if (blockState.getValue(PARENT_BLOCK)) AgeoftheGods.LOGGER.debug("becoming PARENT_BLOCK");
        return blockState;
    }
    @Override
    protected void createBlockStateDefinition(StateDefinition.Builder<Block,BlockState> builder){
        builder.add(MODEL_PART);
        builder.add(FACING);
        builder.add(PARENT_BLOCK);
        builder.add(COMPLETE_STRUCTURE);
    }

    @Override
    public InteractionResult useWithoutItem(BlockState blockstate, Level world, BlockPos pos, Player entity, BlockHitResult hit) {
        super.useWithoutItem(blockstate, world, pos, entity, hit);
        if (entity instanceof ServerPlayer player) {
            if(!blockstate.getBlock().getName().getString().equals(ModBlocks.ALLOY_FURNACE.get().getName().getString()) || pos == null || !blockstate.getValue(COMPLETE_STRUCTURE)) return InteractionResult.PASS;
            AgeoftheGods.LOGGER.debug("OPENING ALLOY FURNACE | POS: " + pos);
            int ModelPart = blockstate.getValue(MODEL_PART);
            BlockPos TargetPos = AlloyFurnaceUpdateHandler.GetParentPosFromModelPart(world, ModelPart, blockstate, pos);
            player.openMenu(new MenuProvider() {
                @Override
                public Component getDisplayName() {
                    return Component.literal("Sigma");
                }

                @Override
                public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) {
                    return new AlloyFurnaceGUI(id, inventory, new FriendlyByteBuf(Unpooled.buffer()).writeBlockPos(TargetPos));
                }
            }, pos);
        }
        return InteractionResult.SUCCESS;
    }


    @Override
    public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
        return new AlloyFurnaceBlockEntity(blockPos,blockState);
    }
}