package electrosphere.server.character;

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

import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.state.server.ServerPlayerViewDirTree;
import electrosphere.entity.types.creature.CreatureEquipData.EquippedItem;
import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.EntityLookupUtils;

/**
 * Deals with spawning player characters
 */
public class PlayerCharacterCreation {
    
    /**
     * Spawns the player's character
     * @param connectionHandler The connection handler of the player
     */
    public static void spawnPlayerCharacter(ServerConnectionHandler connectionHandler){
        Player playerObject = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
        Realm realm = Globals.realmManager.getRealms().iterator().next();

        //
        //get template
        CreatureTemplate template = connectionHandler.getCurrentCreatureTemplate();
        String raceName = template.getCreatureType();

        //
        //spawn entity in world
        Vector3d spawnPoint = realm.getSpawnPoint();
        Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(spawnPoint.x,spawnPoint.y,spawnPoint.z),raceName,template);

        //
        //now that creature has been spawned, need to create all attached items
        if(template != null && template.getCreatureEquipData() != null && template.getCreatureEquipData().getSlots() != null){
            for(String equipSlotId : template.getCreatureEquipData().getSlots()){

                //spawn the item in the world
                EquippedItem itemDefinition = template.getCreatureEquipData().getSlotItem(equipSlotId);
                Entity itemInWorld = ItemUtils.serverSpawnBasicItem(realm, EntityUtils.getPosition(newPlayerEntity), itemDefinition.getItemType());

                //add the item to the creature's inventory
                Entity itemInInventory = InventoryUtils.serverAttemptStoreItem(newPlayerEntity, EntityLookupUtils.getEntityById(itemInWorld.getId()));

                //equip the item to the slot defined in the template
                ServerEquipState serverEquipState = ServerEquipState.getEquipState(newPlayerEntity);
                serverEquipState.commandAttemptEquip(itemInInventory,serverEquipState.getEquipPoint(equipSlotId));
            }
        }

        //
        //attach entity to player object
        LoggerInterface.loggerEngine.INFO("Spawned entity for player. Entity id: " + newPlayerEntity.getId() + " Player id: " + playerObject.getId());
        int playerCharacterId = newPlayerEntity.getId();
        connectionHandler.setPlayerEntityId(playerCharacterId);
        CreatureUtils.setControllerPlayerId(newPlayerEntity, connectionHandler.getPlayerId());
        //custom player btrees
        addPlayerServerBTrees(newPlayerEntity);
        //attach player object to player character
        playerObject.setPlayerEntity(newPlayerEntity);
        playerObject.setWorldPos(new Vector3i(
            realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.x),
            realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.y),
            realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.z)
        ));
        realm.getDataCellManager().addPlayerToRealm(playerObject);

        //
        //error checking
        Realm searchedRealm = Globals.realmManager.getEntityRealm(newPlayerEntity);
        if(searchedRealm == null){
            LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Player entity created but not attached to a realm!"));
        }
    }

    /**
     * Adds behavior trees that are unique to players a given entity
     * @param entity The entity to add to
     */
    static void addPlayerServerBTrees(Entity entity){
        ServerPlayerViewDirTree.attachServerPlayerViewDirTree(entity);
    }

}
