using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Mathematics;

[System.Serializable]
public struct Octave
{
    public float amplitude;
    public float frequency;
    public NoiseType type;
}

[System.Serializable]
public enum NoiseType
{
    MathfPerlin,
    MathematicsPerlin,
    Simplex,
    Celluar
}

public class TerrainGenerator : MonoBehaviour
{
    public Terrain terrain;

    public Terrain[] terrains;

    public List<Octave> octaves;

    [Tooltip("The seed of the generation.")]
    public Vector2 crawlStartPosition;

    public bool generateNewSeed = true;

    public bool refresh;

    [Tooltip("How fine grain the generated terrain will be. Larger values = more precise.")]
    public int xSamples = 1000, ySamples = 1000;

    public virtual void Generate()
    {
        float[,] heights = new float[xSamples, ySamples];

        if (generateNewSeed)
        {
            crawlStartPosition = RNG.GetRandomVector2(-xSamples, -ySamples, xSamples, ySamples);
        }

        foreach (var octave in octaves)
        {
            for (int x = 0; x < xSamples; x++)
            {
                for (int y = 0; y < ySamples; y++)
                {
                    float2 crawlPos = new(x * octave.frequency + crawlStartPosition.x, y * octave.frequency + crawlStartPosition.y);
                    float addition;

                    switch (octave.type)
                    {
                        default:
                        case NoiseType.MathfPerlin:
                            addition = Mathf.PerlinNoise(crawlPos.x, crawlPos.y);
                            break;
                        case NoiseType.MathematicsPerlin:
                            addition = noise.cnoise(crawlPos) / 2.3f + 0.5f;
                            break;
                        case NoiseType.Simplex:
                            addition = noise.snoise(crawlPos) / 4.6f + 0.5f;
                            break;
                        case NoiseType.Celluar:
                            addition = noise.cellular(crawlPos).x / 2.3f + 0.5f;
                            break;
                    }
                    heights[x, y] += addition * octave.amplitude;
                }
            }
        }

        terrain.terrainData.SetHeights(0, 0, heights);
    }

    private void Start()
    {
        terrains = GetComponentsInChildren<Terrain>();
        Generate();
    }

    private void Update()
    {
        if (refresh)
        {
            refresh = false;
            Generate();
        }
    }
}