package jesse.keeblarcraft.CustomBlocks.Blocks;

import jesse.keeblarcraft.ChatStuff.ChatFormatting;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
import jesse.keeblarcraft.FactionMgr.FactionConfig;
import jesse.keeblarcraft.Utils.CommonStructures.Position3d;
import org.jetbrains.annotations.Nullable;

import jesse.keeblarcraft.CustomBlocks.BlockEntities.BlockEntityRegistration;
import jesse.keeblarcraft.CustomBlocks.BlockEntities.FactionBlockEntity;
import jesse.keeblarcraft.FactionMgr.FactionManager;
import net.minecraft.block.*;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.NamedScreenHandlerFactory;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.ItemScatterer;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public class FactionBaseBlock extends BlockWithEntity implements BlockEntityProvider {
    // public static final VoxelShape SHAPE = Block.createCuboidShape(0, 0, 0, 16, 12, 16);
    private String faction; // Faction attached to this block

    public FactionBaseBlock(Settings settings) {
        super(settings);
    }

    // @Override
    // protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
    //     return SHAPE;
    // }

    @Override
    public BlockRenderType getRenderType(BlockState state) {
        return BlockRenderType.MODEL;
    }

    @Override
    public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {
        if (world.isClient()) {
            return;
        }

        if (placer != null && placer.isPlayer()) {
            // We need to run faction checks here and make sure this player owns a faction otherwise they are NOT allowed to place it!
            ServerPlayerEntity player = (ServerPlayerEntity) placer;
            String fac = FactionManager.GetInstance().GetFactionOfPlayer(player.getUuidAsString());

            // We need to verify the faction does not already have a block placed in the world; and make sure the placer
            // is the owner of the faction.
            Boolean canPlaceFactionBlock = FactionManager.GetInstance().CanPlaceFactionBlock(fac);
            System.out.println("hasFacBlock: " + canPlaceFactionBlock);
            FactionConfig.VALID_FACTION_ROLES role = FactionManager.GetInstance().GetPlayerRole(fac, placer.getUuidAsString());
            System.out.println("Can place block?: " + canPlaceFactionBlock);
            System.out.println("Role: " + role.name());

            if (canPlaceFactionBlock && role == FactionConfig.VALID_FACTION_ROLES.OWNER) {
                FactionBlockEntity bEntity = (FactionBlockEntity) world.getBlockEntity(pos);
                // Update block entity - this is the "ultimate success" portion
                if (bEntity != null) {
                    bEntity.SetFaction(fac);
                    // Enable chunk loading
                    world.getChunkManager().setChunkForced(world.getChunk(pos).getPos(), true);
                    faction = fac;
                    FactionManager.GetInstance().SetFactionBlock(faction, new Position3d(pos.getX(), pos.getY(), pos.getZ()));
                    player.sendMessage(Text.of(ChatMsg.ColorMsg("This block now begins to the " + fac + " faction!", ChatFormatting.COLOR_CODE.GOLD)));
                }
            } else if (canPlaceFactionBlock) {
                player.sendMessage(Text.of(ChatMsg.ColorMsg("You cannot place more than one faction block per faction!", ChatFormatting.COLOR_CODE.RED)));
                world.breakBlock(pos, true);
            } else {
                player.sendMessage(Text.of(ChatMsg.ColorMsg("You do not appear to be in a faction or are not the leader of this faction. You cannot place this block!", ChatFormatting.COLOR_CODE.RED)));
                world.breakBlock(pos, true);
            }
        } else {
            // Only a player should be able to place the block in order to set faction appropriately. Destroy!
            world.breakBlock(pos, true);
        }
    }

    @Override
    public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
        return new FactionBlockEntity(pos, state, faction);
    }

    // If block is destroyed; drop inventory
    @Override
    public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
        if (state.getBlock() != newState.getBlock()) {
            BlockEntity blockEntity = world.getBlockEntity(pos);
            if (blockEntity instanceof FactionBlockEntity) {
                ItemScatterer.spawn(world, pos, (FactionBlockEntity) blockEntity);
                world.updateComparators(pos, this);
            }

            // This is pulled directly from #AbstractBlock$AbstractBlockState.class:onStateReplaced
            // Catch if the block is being broken. Update our block entity to reset all
            if (state.hasBlockEntity() && !state.isOf(newState.getBlock())) {
                FactionBlockEntity bEntity = (FactionBlockEntity) world.getBlockEntity(pos);
                if (bEntity != null) {
                    bEntity.ResetBlock();
                }
            }

            // Disable chunk loading
            world.getChunkManager().setChunkForced(world.getChunk(pos).getPos(), false);
            FactionManager.GetInstance().RemoveFactionBlock(faction, new Position3d(pos.getX(), pos.getY(), pos.getZ()));
            super.onStateReplaced(state, world, pos, newState, moved);
        }
    }

    // Open the inventory
    // Calls ScreenHandler inside createMenu of entity class
    @Override
    public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
        // Server side handling is different from that of client side handling; we MUST check if we are on a server first because then we must
        // request information about this block entity from the server
        System.out.println("onUse of faction base block called");
        if (!world.isClient()) {
            NamedScreenHandlerFactory screenHandlerFactory = (FactionBlockEntity) world.getBlockEntity(pos);

            if (screenHandlerFactory != null) {
                player.openHandledScreen(screenHandlerFactory);
            }
        }
        return ActionResult.SUCCESS;
    }

    @Override
    public <T extends BlockEntity> BlockEntityTicker<T> getTicker(World world, BlockState state, BlockEntityType<T> type) {
        return validateTicker(type, BlockEntityRegistration.FACTION_BLOCK_ENTITY,
        (world1, pos, state1, blockEntity) -> blockEntity.tick(world1, pos, state1));
    }
}
