// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.builtin.mounts;

import com.hypixel.hytale.server.core.asset.type.blocktype.config.mountpoints.BlockMountPoint;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.protocol.BlockMountType;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.server.core.modules.block.BlockModule;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.server.core.universe.world.chunk.BlockComponentChunk;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;

public final class BlockMountAPI
{
    private BlockMountAPI() {
    }
    
    public static BlockMountResult mountOnBlock(final Ref<EntityStore> entity, final CommandBuffer<EntityStore> commandBuffer, final Vector3i targetBlock, final Vector3f interactPos) {
        final MountedComponent existingMounted = commandBuffer.getComponent(entity, MountedComponent.getComponentType());
        if (existingMounted != null) {
            return DidNotMount.ALREADY_MOUNTED;
        }
        final World world = entity.getStore().getExternalData().getWorld();
        final WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z));
        if (chunk == null) {
            return DidNotMount.CHUNK_NOT_FOUND;
        }
        final Ref<ChunkStore> chunkRef = chunk.getReference();
        if (chunkRef == null) {
            return DidNotMount.CHUNK_REF_NOT_FOUND;
        }
        final ChunkStore chunkStore = world.getChunkStore();
        final BlockComponentChunk blockComponentChunk = chunkStore.getStore().getComponent(chunkRef, BlockComponentChunk.getComponentType());
        if (blockComponentChunk == null) {
            return DidNotMount.CHUNK_REF_NOT_FOUND;
        }
        final BlockType blockType = world.getBlockType(targetBlock);
        if (blockType == null) {
            return DidNotMount.INVALID_BLOCK;
        }
        final int rotationIndex = chunk.getRotationIndex(targetBlock.x, targetBlock.y, targetBlock.z);
        final int blockIndex = ChunkUtil.indexBlockInColumn(targetBlock.x, targetBlock.y, targetBlock.z);
        Ref<ChunkStore> blockRef = blockComponentChunk.getEntityReference(blockIndex);
        if (blockRef == null || !blockRef.isValid()) {
            final Holder<ChunkStore> blockHolder = ChunkStore.REGISTRY.newHolder();
            blockHolder.putComponent(BlockModule.BlockStateInfo.getComponentType(), new BlockModule.BlockStateInfo(blockIndex, chunkRef));
            blockRef = world.getChunkStore().getStore().addEntity(blockHolder, AddReason.SPAWN);
            if (blockRef == null || !blockRef.isValid()) {
                return DidNotMount.BLOCK_REF_NOT_FOUND;
            }
        }
        BlockMountType blockMountType = null;
        BlockMountPoint[] mountPointsForBlock = null;
        if (blockType.getSeats() != null) {
            blockMountType = BlockMountType.Seat;
            mountPointsForBlock = blockType.getSeats().getRotated(rotationIndex);
        }
        else {
            if (blockType.getBeds() == null) {
                return DidNotMount.UNKNOWN_BLOCKMOUNT_TYPE;
            }
            blockMountType = BlockMountType.Bed;
            mountPointsForBlock = blockType.getBeds().getRotated(rotationIndex);
        }
        BlockMountComponent blockMountComponent = world.getChunkStore().getStore().getComponent(blockRef, BlockMountComponent.getComponentType());
        if (blockMountComponent == null) {
            blockMountComponent = new BlockMountComponent(blockMountType, targetBlock, blockType, rotationIndex);
            world.getChunkStore().getStore().addComponent(blockRef, BlockMountComponent.getComponentType(), blockMountComponent);
        }
        if (mountPointsForBlock == null || mountPointsForBlock.length == 0) {
            return DidNotMount.NO_MOUNT_POINT_FOUND;
        }
        final BlockMountPoint pickedMountPoint = blockMountComponent.findAvailableSeat(targetBlock, mountPointsForBlock, interactPos);
        if (pickedMountPoint == null) {
            return DidNotMount.NO_MOUNT_POINT_FOUND;
        }
        final TransformComponent transformComponent = commandBuffer.getComponent(entity, TransformComponent.getComponentType());
        if (transformComponent != null) {
            final Vector3f position = pickedMountPoint.computeWorldSpacePosition(blockMountComponent.getBlockPos());
            final Vector3f rotationEuler = pickedMountPoint.computeRotationEuler(blockMountComponent.getExpectedRotation());
            transformComponent.setPosition(position.toVector3d());
            transformComponent.setRotation(rotationEuler);
        }
        final MountedComponent mountedComponent = new MountedComponent(blockRef, new Vector3f(0.0f, 0.0f, 0.0f), blockMountType);
        commandBuffer.addComponent(entity, MountedComponent.getComponentType(), mountedComponent);
        blockMountComponent.putSeatedEntity(pickedMountPoint, entity);
        return new Mounted(blockType, mountedComponent);
    }
    
    record Mounted(BlockType blockType, MountedComponent component) implements BlockMountResult {}
    
    public enum DidNotMount implements BlockMountResult
    {
        CHUNK_NOT_FOUND, 
        CHUNK_REF_NOT_FOUND, 
        BLOCK_REF_NOT_FOUND, 
        INVALID_BLOCK, 
        ALREADY_MOUNTED, 
        UNKNOWN_BLOCKMOUNT_TYPE, 
        NO_MOUNT_POINT_FOUND;
    }
    
    public sealed interface BlockMountResult permits Mounted, DidNotMount
    {
    }
}
