package electrosphere.server.content;

import java.util.List;
import java.util.Random;

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

import electrosphere.entity.types.foliage.FoliageUtils;
import electrosphere.game.data.biome.BiomeData;
import electrosphere.game.data.biome.BiomeFoliageDescription;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import io.github.studiorailgun.NoiseUtils;

/**
 * Generates content for a given datacell
 */
public class ServerContentGenerator {

    /**
     * The seed of the foliage
     */
    public static final int FOLIAGE_SEED = 0;

    /**
     * Adjustment applied to generated height value to approximate the height of the actual terrain.
     * The voxels don't generate QUITE to the height of the heightmap, so this is applied to make the value line up better for entity placement.
     */
    public static final float HEIGHT_MANUAL_ADJUSTMENT = -0.35f;

    /**
     * Generates content for a given data cell
     * @param realm The realm
     * @param cell The cell
     * @param worldPos The world position of the cell
     * @param randomizer The randomizer
     */
    public static void generateContent(Realm realm, ServerDataCell cell, Vector3i worldPos, long randomizer){
        //verify we have everything for chunk content gen
        if(realm.getServerWorldData() == null && realm.getServerWorldData().getServerTerrainManager() == null && realm.getServerWorldData().getServerTerrainManager().getModel() == null){
            throw new Error(
                "Trying to generate content for a realm that does not have a terrain model defined!\n" +
                realm.getServerWorldData() + "\n" +
                realm.getServerWorldData().getServerTerrainManager() + "\n" +
                realm.getServerWorldData().getServerTerrainManager().getModel()
            );
        }

        //setup
        Random random = new Random(randomizer);


        //generate foliage
        BiomeData biome = null;
        if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null && realm.getServerWorldData().getServerTerrainManager().getModel() != null){
            biome = realm.getServerWorldData().getServerTerrainManager().getModel().getClosestSurfaceBiome(worldPos.x, worldPos.z);
        }
        List<BiomeFoliageDescription> foliageDescriptions = biome.getSurfaceGenerationParams().getFoliageDescriptions();
        if(foliageDescriptions != null){
            for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
                for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
                    double height = realm.getServerWorldData().getServerTerrainManager().getElevation(worldPos.x, worldPos.z, x, z) + HEIGHT_MANUAL_ADJUSTMENT;
                    if(
                        realm.getServerWorldData().convertVoxelToRealSpace(0, worldPos.y) < height &&
                        realm.getServerWorldData().convertVoxelToRealSpace(ServerTerrainChunk.CHUNK_DIMENSION, worldPos.y) > height
                    ){
                        for(BiomeFoliageDescription foliageDescription : foliageDescriptions){
                            double scale = foliageDescription.getScale();
                            double regularity = foliageDescription.getRegularity();
                            double threshold = foliageDescription.getThreshold();
                            double realX = realm.getServerWorldData().convertVoxelToRealSpace(x, worldPos.x);
                            double realZ = realm.getServerWorldData().convertVoxelToRealSpace(z, worldPos.z);
                            if(NoiseUtils.relaxedPointGen(realX * scale, realZ * scale, regularity, threshold) > 0){
                                String type = foliageDescription.getEntityIDs().get(random.nextInt(0,foliageDescription.getEntityIDs().size()));
                                FoliageUtils.serverSpawnTreeFoliage(
                                    realm,
                                    new Vector3d(
                                        realX,
                                        height,
                                        realZ
                                    ),
                                    type,
                                    random.nextLong()
                                );
                            }
                        }
                    }
                }
            }
        }

    }
    
}
