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

package com.hypixel.hytale.builtin.portals.interactions;

import com.hypixel.hytale.builtin.portals.resources.PortalWorld;
import java.util.concurrent.CompletableFuture;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import java.util.UUID;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import java.util.concurrent.Executor;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.builtin.instances.InstancesPlugin;
import com.hypixel.hytale.server.core.entity.entities.player.pages.CustomUIPage;
import com.hypixel.hytale.builtin.portals.ui.PortalDeviceActivePage;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
import com.hypixel.hytale.math.vector.Transform;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.server.core.modules.block.BlockModule;
import com.hypixel.hytale.builtin.portals.components.PortalDevice;
import com.hypixel.hytale.protocol.InteractionState;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.modules.interaction.interaction.CooldownHandler;
import com.hypixel.hytale.math.vector.Vector3i;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.entity.InteractionContext;
import com.hypixel.hytale.protocol.InteractionType;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.protocol.WaitForDataFrom;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import javax.annotation.Nonnull;
import java.time.Duration;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.client.SimpleBlockInteraction;

public class EnterPortalInteraction extends SimpleBlockInteraction
{
    @Nonnull
    public static final Duration MINIMUM_TIME_IN_WORLD;
    @Nonnull
    public static final BuilderCodec<EnterPortalInteraction> CODEC;
    private static final Message MESSAGE_PORTALS_DEVICE_REF_INVALID;
    private static final Message MESSAGE_PORTALS_DEVICE_WORLD_IS_DEAD;
    private static final Message MESSAGE_PORTALS_DEVICE_NO_SPAWN;
    private static final Message MESSAGE_PORTALS_DEVICE_BLOCK_ENTITY_REF_INVALID;
    static final /* synthetic */ boolean $assertionsDisabled;
    
    @Nonnull
    @Override
    public WaitForDataFrom getWaitForDataFrom() {
        return WaitForDataFrom.Server;
    }
    
    @Override
    protected void interactWithBlock(@Nonnull final World world, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final InteractionType type, @Nonnull final InteractionContext context, @Nullable final ItemStack itemInHand, @Nonnull final Vector3i targetBlock, @Nonnull final CooldownHandler cooldownHandler) {
        final Ref<EntityStore> ref = context.getEntity();
        final Player playerComponent = commandBuffer.getComponent(ref, Player.getComponentType());
        if (playerComponent == null) {
            context.getState().state = InteractionState.Failed;
            return;
        }
        if (playerComponent.getSinceLastSpawnNanos() < EnterPortalInteraction.MINIMUM_TIME_IN_WORLD.toNanos()) {
            context.getState().state = InteractionState.Failed;
            return;
        }
        final PortalDevice portalDevice = BlockModule.get().getComponent(PortalDevice.getComponentType(), world, targetBlock.x, targetBlock.y, targetBlock.z);
        if (portalDevice == null) {
            context.getState().state = InteractionState.Failed;
            return;
        }
        final WorldChunk chunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(targetBlock.x, targetBlock.z));
        if (chunk == null) {
            context.getState().state = InteractionState.Failed;
            return;
        }
        final BlockType blockType = chunk.getBlockType(targetBlock);
        if (blockType == null) {
            context.getState().state = InteractionState.Failed;
            return;
        }
        final RotationTuple rotation = chunk.getRotation(targetBlock.x, targetBlock.y, targetBlock.z);
        final double yaw = rotation.yaw().getRadians() + 3.141592653589793;
        final Transform returnTransform = new Transform(targetBlock.x + 0.5, targetBlock.y + 0.5, targetBlock.z + 0.5, 0.0f, (float)yaw, 0.0f);
        final World targetWorld = portalDevice.getDestinationWorld();
        if (targetWorld == null) {
            playerComponent.sendMessage(EnterPortalInteraction.MESSAGE_PORTALS_DEVICE_WORLD_IS_DEAD);
            context.getState().state = InteractionState.Failed;
            return;
        }
        final UUIDComponent uuidComponent = commandBuffer.getComponent(ref, UUIDComponent.getComponentType());
        assert uuidComponent != null;
        final UUID playerUuid = uuidComponent.getUuid();
        fetchTargetWorldState(targetWorld, playerUuid).thenAcceptAsync(state -> {
            if (!ref.isValid()) {
                playerComponent.sendMessage(EnterPortalInteraction.MESSAGE_PORTALS_DEVICE_REF_INVALID);
                context.getState().state = InteractionState.Failed;
            }
            else {
                switch (state.ordinal()) {
                    case 1: {
                        playerComponent.sendMessage(EnterPortalInteraction.MESSAGE_PORTALS_DEVICE_WORLD_IS_DEAD);
                        context.getState().state = InteractionState.Failed;
                        break;
                    }
                    case 3: {
                        playerComponent.sendMessage(EnterPortalInteraction.MESSAGE_PORTALS_DEVICE_NO_SPAWN);
                        context.getState().state = InteractionState.Failed;
                        break;
                    }
                    case 2: {
                        final PlayerRef playerRefComponent = commandBuffer.getComponent(ref, PlayerRef.getComponentType());
                        if (!EnterPortalInteraction.$assertionsDisabled && playerRefComponent == null) {
                            throw new AssertionError();
                        }
                        else {
                            final Ref<ChunkStore> blockEntityRef = BlockModule.getBlockEntity(world, targetBlock.x, targetBlock.y, targetBlock.z);
                            if (blockEntityRef == null || !blockEntityRef.isValid()) {
                                playerComponent.sendMessage(EnterPortalInteraction.MESSAGE_PORTALS_DEVICE_BLOCK_ENTITY_REF_INVALID);
                                context.getState().state = InteractionState.Failed;
                                return;
                            }
                            else {
                                final PortalDeviceActivePage activePage = new PortalDeviceActivePage(playerRefComponent, portalDevice.getConfig(), blockEntityRef);
                                playerComponent.getPageManager().openCustomPage(ref, world.getEntityStore().getStore(), activePage);
                                break;
                            }
                        }
                        break;
                    }
                    case 0: {
                        InstancesPlugin.teleportPlayerToInstance(ref, commandBuffer, targetWorld, returnTransform);
                        break;
                    }
                }
            }
        }, (Executor)world);
    }
    
    @Nonnull
    private static CompletableFuture<TargetWorldState> fetchTargetWorldState(@Nonnull final World world, @Nonnull final UUID playerId) {
        return CompletableFuture.supplyAsync(() -> {
            final PortalWorld portalWorld = world.getEntityStore().getStore().getResource(PortalWorld.getResourceType());
            if (!portalWorld.exists()) {
                return TargetWorldState.WORLD_DEAD;
            }
            else if (portalWorld.getSpawnPoint() == null) {
                return TargetWorldState.NO_SPAWN_AVAILABLE;
            }
            else if (portalWorld.getDiedInWorld().contains(playerId)) {
                return TargetWorldState.DIED_IN_WORLD;
            }
            else {
                return TargetWorldState.OKAY;
            }
        }, world);
    }
    
    @Override
    protected void simulateInteractWithBlock(@Nonnull final InteractionType type, @Nonnull final InteractionContext context, @Nullable final ItemStack itemInHand, @Nonnull final World world, @Nonnull final Vector3i targetBlock) {
    }
    
    static {
        MINIMUM_TIME_IN_WORLD = Duration.ofMillis(3000L);
        CODEC = BuilderCodec.builder(EnterPortalInteraction.class, EnterPortalInteraction::new, SimpleBlockInteraction.CODEC).build();
        MESSAGE_PORTALS_DEVICE_REF_INVALID = Message.translation("server.portals.device.refInvalid");
        MESSAGE_PORTALS_DEVICE_WORLD_IS_DEAD = Message.translation("server.portals.device.worldIsDead");
        MESSAGE_PORTALS_DEVICE_NO_SPAWN = Message.translation("server.portals.device.worldNoSpawn");
        MESSAGE_PORTALS_DEVICE_BLOCK_ENTITY_REF_INVALID = Message.translation("server.portals.device.blockEntityRefInvalid");
    }
    
    private enum TargetWorldState
    {
        OKAY, 
        WORLD_DEAD, 
        DIED_IN_WORLD, 
        NO_SPAWN_AVAILABLE;
    }
}
