package electrosphere.server.character;

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

import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.state.server.ServerPlayerViewDirTree;
import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.Realm;

/**
 * Deals with spawning player characters
 */
public class PlayerCharacterCreation {
    
    /**
     * Spawns the player's character
     * @param connectionHandler The connection handler of the player
     */
    public static Entity 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 = PlayerCharacterCreation.solveSpawnPoint(realm, connectionHandler);
        Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(spawnPoint.x,spawnPoint.y,spawnPoint.z),raceName,template);

        //
        //attach entity to player object
        LoggerInterface.loggerEngine.INFO("Spawned entity for player. Entity id: " + newPlayerEntity.getId() + " Player id: " + playerObject.getId());
        PlayerCharacterCreation.attachEntityToPlayerObject(newPlayerEntity,playerObject,connectionHandler);
        playerObject.setWorldPos(new Vector3i(
            realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.x),
            realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.y),
            realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.z)
        ));
        realm.getDataCellManager().addPlayerToRealm(playerObject);

        //must come after the player is assigned, otherwise the player will not get the item attachment messages
        CreatureUtils.serverApplyTemplate(realm, newPlayerEntity, template);

        //
        //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!"));
        }

        return newPlayerEntity;
    }

    /**
     * Attachs an entity to a player object
     * @param entity The entity
     * @param playerObject The player object
     * @param serverConnectionHandler The connection handler
     */
    public static void attachEntityToPlayerObject(Entity entity, Player playerObject, ServerConnectionHandler serverConnectionHandler){
        int playerCharacterId = entity.getId();
        serverConnectionHandler.setPlayerEntityId(playerCharacterId);
        CreatureUtils.setControllerPlayerId(entity, serverConnectionHandler.getPlayerId());
        Player player = serverConnectionHandler.getPlayer();
        player.setPlayerEntity(entity);
        //custom player btrees
        PlayerCharacterCreation.addPlayerServerBTrees(entity);
    }

    /**
     * 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);
    }

    /**
     * Solves the spawn point for the player
     * @param realm The realm that the entity is being spawned in
     * @param connectionHandler The connection object
     * @return The spawn point for the player
     */
    public static Vector3d solveSpawnPoint(Realm realm, ServerConnectionHandler connectionHandler){
        Vector3d spawnPoint = realm.getSpawnPoint();
        return spawnPoint;
    }

}
