package electrosphere.client.script;

import org.graalvm.polyglot.HostAccess.Export;
import org.joml.Vector3d;
import org.joml.Vector3i;

import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.client.terrain.editing.TerrainEditing;
import electrosphere.collision.CollisionEngine;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.server.terrain.manager.ServerTerrainChunk;

/**
 * Utilities for interacting with voxels from the client
 */
public class ScriptClientVoxelUtils {
    
    /**
     * Increment to edit terrain by
     */
    static final float EDIT_INCREMENT = 0.1f;

    //vertical offset from cursor position to spawn things at
    static final Vector3d cursorVerticalOffset = new Vector3d(0,0.05,0);

    /**
     * Applies the current voxel palette where the player's cursor is looking
     */
    @Export
    public static void applyEdit(){
        CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
        Entity camera = Globals.playerCamera;
        if(
            collisionEngine != null &&
            camera != null
        ){
            Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
            Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
            Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), CollisionEngine.DEFAULT_INTERACT_DISTANCE);
            if(cursorPos == null){
                cursorPos = new Vector3d(centerPos).add(new Vector3d(eyePos).mul(-CollisionEngine.DEFAULT_INTERACT_DISTANCE));
            }
            if(Globals.clientSelectedVoxelType != null){
                TerrainEditing.editTerrain(cursorPos, 1.1f, Globals.clientSelectedVoxelType.getId(), EDIT_INCREMENT);
            }
        }
    }

    /**
     * Applies the current voxel palette where the player's cursor is looking
     */
    @Export
    public static void spawnWater(){
        CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
        Entity camera = Globals.playerCamera;
        if(
            collisionEngine != null &&
            camera != null &&
            Globals.realmManager != null &&
            Globals.realmManager.first() != null &&
            Globals.realmManager.first().getServerWorldData() != null &&
            Globals.realmManager.first().getServerWorldData().getServerFluidManager() != null
        ){
            Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
            Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
            Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), CollisionEngine.DEFAULT_INTERACT_DISTANCE);
            if(cursorPos == null){
                cursorPos = new Vector3d(centerPos).add(new Vector3d(eyePos).normalize().mul(-CollisionEngine.DEFAULT_INTERACT_DISTANCE));
            }
            cursorPos = cursorPos.add(cursorVerticalOffset);
            Vector3i worldPos = new Vector3i(
                (int)(cursorPos.x / ServerTerrainChunk.CHUNK_DIMENSION),
                (int)(cursorPos.y / ServerTerrainChunk.CHUNK_DIMENSION),
                (int)(cursorPos.z / ServerTerrainChunk.CHUNK_DIMENSION)
            );
            Vector3i voxelPos = new Vector3i(
                (int)(Math.ceil(cursorPos.x) % ServerTerrainChunk.CHUNK_DIMENSION),
                (int)(Math.ceil(cursorPos.y) % ServerTerrainChunk.CHUNK_DIMENSION),
                (int)(Math.ceil(cursorPos.z) % ServerTerrainChunk.CHUNK_DIMENSION)
            );
            Globals.realmManager.first().getServerWorldData().getServerFluidManager().deformFluidAtLocationToValue(worldPos, voxelPos, 1.0f, 0);
        }
    }

    /**
     * Tries to dig with whatever tool is equipped
     */
    @Export
    public static void dig(){
        CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
        Entity camera = Globals.playerCamera;
        if(
            collisionEngine != null &&
            camera != null
        ){
            Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
            Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
            Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), CollisionEngine.DEFAULT_INTERACT_DISTANCE);
            if(cursorPos == null){
                cursorPos = new Vector3d(centerPos).add(new Vector3d(eyePos).mul(-CollisionEngine.DEFAULT_INTERACT_DISTANCE));
            }
            if(Globals.clientSelectedVoxelType != null){
                TerrainEditing.removeTerrainGated(cursorPos, 1.1f, Globals.clientSelectedVoxelType.getId(), EDIT_INCREMENT);
            }
        }
    }

}
