package electrosphere.server.player;

import org.joml.Vector3d;
import org.joml.Vector3i;

import electrosphere.client.interact.ItemActions;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.state.block.ServerBlockTree;
import electrosphere.entity.state.equip.ServerToolbarState;
import electrosphere.entity.state.life.ServerLifeTree;
import electrosphere.entity.types.common.CommonEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.game.data.common.interact.InteractionData;
import electrosphere.game.data.creature.type.CreatureData;
import electrosphere.game.data.creature.type.block.BlockVariant;
import electrosphere.game.data.item.Item;
import electrosphere.game.data.item.ItemUsage;
import electrosphere.game.server.world.ServerWorldData;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.server.block.editing.ServerBlockEditing;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.utils.ServerScriptUtils;

/**
 * Class for handling 
 */
public class PlayerActions {

    /**
     * Attempts to perform an action a player requested
     * @param connectionHandler The player's connection handler
     * @param message The network message that encapsulates the requested action
     */
    public static void attemptPlayerAction(ServerConnectionHandler connectionHandler, InventoryMessage message){
        Entity playerEntity = EntityLookupUtils.getEntityById(connectionHandler.getPlayerEntityId());

        if(message.getitemActionCode() == ItemActions.ITEM_ACTION_CODE_SECONDARY){
            ServerToolbarState serverToolbarState = ServerToolbarState.getServerToolbarState(playerEntity);
            if(serverToolbarState != null && serverToolbarState.getRealWorldItem() != null){
                Item item = Globals.gameConfigCurrent.getItemMap().getItem(serverToolbarState.getRealWorldItem());
                CreatureData creatureData = Globals.gameConfigCurrent.getCreatureTypeLoader().getType(CreatureUtils.getType(playerEntity));
                ServerBlockTree serverBlockTree = ServerBlockTree.getServerBlockTree(playerEntity);

                //check block status
                boolean shouldBlock = false;
                if(creatureData.getBlockSystem() != null && creatureData.getBlockSystem().getAllVariants() != null && serverBlockTree != null){
                    for(BlockVariant variant : creatureData.getBlockSystem().getAllVariants()){
                        if(variant.getVariantId().equals(serverBlockTree.getCurrentBlockVariant())){
                            shouldBlock = true;
                            break;
                        }
                    }
                }

                //actually perform actions
                if(shouldBlock){
                    PlayerActions.block(playerEntity, message);
                } else if(item.getSecondaryUsage() != null){
                    PlayerActions.secondaryUsage(playerEntity, item, message);
                }
            }
        }
    }

    /**
     * Attempts to block
     */
    private static void block(Entity playerEntity, InventoryMessage message){
        ServerBlockTree serverBlockTree = ServerBlockTree.getServerBlockTree(playerEntity);
        if(serverBlockTree != null){
            if(message.getitemActionCodeState() == ItemActions.ITEM_ACTION_CODE_STATE_ON){
                serverBlockTree.start();
            } else {
                serverBlockTree.stop();
            }
        }
    }

    /**
     * Performs various secondary usages
     * @param playerEntity The player's entity
     * @param item The item data
     * @param message The message
     */
    private static void secondaryUsage(Entity playerEntity, Item item, InventoryMessage message){
        ItemUsage secondaryUsage = item.getSecondaryUsage();
        Realm playerRealm = Globals.realmManager.getEntityRealm(playerEntity);

        //entity spawning
        if(secondaryUsage.getSpawnEntityId() != null){
            Vector3d spawnPos = new Vector3d(message.getviewTargetX(),message.getviewTargetY(),message.getviewTargetZ());
            CommonEntityUtils.serverSpawnBasicObject(playerRealm, spawnPos, secondaryUsage.getSpawnEntityId());
        }

        //voxel block editing
        if(secondaryUsage.getBlockId() != null){
            ServerWorldData serverWorldData = playerRealm.getServerWorldData();

            //clamp the placement pos to the block grid..
            Vector3d placementPos = new Vector3d(message.getviewTargetX(),message.getviewTargetY(),message.getviewTargetZ());
            Vector3i worldPos = serverWorldData.convertRealToWorldSpace(placementPos);
            Vector3i blockPos = serverWorldData.convertRealToLocalBlockSpace(placementPos);


            //actually edit
            ServerBlockEditing.editBlockChunk(playerRealm, worldPos, blockPos, (short)(int)secondaryUsage.getBlockId(), (short)0);
            LoggerInterface.loggerEngine.DEBUG("Place block type " + secondaryUsage.getBlockId() + " at " + placementPos + " -> " + worldPos + " " + blockPos);
        }
    }


    /**
     * Attempts to perform an action a player requested
     * @param connectionHandler The player's connection handler
     * @param target The target if the interaction
     * @param signal The type of interaction
     */
    public static void attemptInteraction(ServerConnectionHandler connectionHandler, Entity target, String signal){
        Entity playerEntity = EntityLookupUtils.getEntityById(connectionHandler.getPlayerEntityId());
        switch(signal){
            case InteractionData.ON_INTERACT_HARVEST: {
                if(ServerLifeTree.hasServerLifeTree(target)){
                    ServerLifeTree serverLifeTree = ServerLifeTree.getServerLifeTree(target);
                    serverLifeTree.kill();
                }
                ServerScriptUtils.fireSignalOnEntity(playerEntity, "entityInteractHarvest", target);
            } break;
            default: {
                throw new Error("Unsupported signal received! " + signal);
            }
        }
    }
    
}
