using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Chunk : MonoBehaviour
{
    private Mesh mesh;

    private const int MESH_RESOLUTION_X = 64;
    private const int MESH_RESOLUTION_Y = 64;
    public const float CHUNK_SIZE = 64.0f;
    private const float MESH_TILE_RES = CHUNK_SIZE / MESH_RESOLUTION_X;

    private List<GameObject> localPooledPrefabs = new List<GameObject>();

    protected void Awake()
    {
        mesh = new Mesh();
        Vector3[] vertices = new Vector3[MESH_RESOLUTION_X * MESH_RESOLUTION_Y * 4];
        int[] triangles = new int[MESH_RESOLUTION_X*MESH_RESOLUTION_Y*3*2];

        int vertIndex = 0;
        int triangleIndex = 0;

        for(int x=0; x<MESH_RESOLUTION_X; x++)
        {
            for(int y=0; y<MESH_RESOLUTION_Y; y++)
            {
                vertices[vertIndex+0] = (new Vector3(x, 0.0f, y)) * MESH_TILE_RES;
                vertices[vertIndex+1] = (new Vector3(x+1, 0.0f, y)) * MESH_TILE_RES;
                vertices[vertIndex+2] = (new Vector3(x, 0.0f, y+1)) * MESH_TILE_RES;
                vertices[vertIndex+3] = (new Vector3(x+1, 0.0f, y+1)) * MESH_TILE_RES;

                triangles[triangleIndex+0] = vertIndex+2;
                triangles[triangleIndex+1] = vertIndex+1;
                triangles[triangleIndex+2] = vertIndex+0;
                triangles[triangleIndex+3] = vertIndex+1;
                triangles[triangleIndex+4] = vertIndex+2;
                triangles[triangleIndex+5] = vertIndex+3;
                
                vertIndex += 4;
                triangleIndex += 6;
            }
        }

        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.Optimize();
        mesh.RecalculateNormals();

        GetComponent<MeshFilter>().mesh = mesh;
        MeshCollider meshCollider = GetComponent<MeshCollider>();
        meshCollider.sharedMesh = mesh;
    }

    public void UpdateMesh()
    {
        Vector3[] vertices = mesh.vertices;
        Vector3 vertex;
        Vector3 worldSpaceVertexPosition;
        for(int n=0;n<vertices.Length;n++)
        {
            vertex = vertices[n];
            worldSpaceVertexPosition = this.transform.TransformPoint(vertex);
            vertices[n] = new Vector3(vertex.x, TerrainGenerator.Instance.GetHeight(worldSpaceVertexPosition.x, worldSpaceVertexPosition.z), vertex.z);
        }

        mesh.vertices = vertices;
        mesh.RecalculateNormals();
        mesh.RecalculateBounds();
    }

    public void UpdatePosition(Vector3 newPos)
    {
        this.transform.position = newPos;
        foreach(GameObject g in localPooledPrefabs)
            PoolManager.Instance.ReturnInstance(g);

        localPooledPrefabs.Clear();

        List<Vector2> points = PoissonDiscSampling.GeneratePoints(7.0f, new Vector2(CHUNK_SIZE, CHUNK_SIZE));
        Vector2 globalPos = new Vector2(this.transform.position.x, this.transform.position.z);
        foreach(Vector2 point in points)
        {
            Vector2 globalPoint = point + globalPos;
            float noise_scale = 0.1f;
            float noise = Mathf.PerlinNoise(1000.0f + globalPoint.x * noise_scale, 1000.0f + globalPoint.y * noise_scale) * 2.0f - 1.0f;
            float distanceFromPath = TerrainGenerator.Instance.GetDistanceFromPath(globalPoint.x, globalPoint.y);
            float height = TerrainGenerator.Instance.GetHeight(globalPoint.x, globalPoint.y);
            if(height < 16.0f && noise > 0.01f && Mathf.Abs(distanceFromPath) > 1.0f)
            {
                GameObject g = PoolManager.Instance.GetInstance(TerrainGenerator.Instance.TreePrefab);
                if(g != null)
                {
                    g.transform.position = new Vector3(globalPoint.x, height, globalPoint.y);
                    localPooledPrefabs.Add(g);
                }
            }
        }

        if(this.transform.position.x == 0 && this.transform.position.z > 0)
        {
            int MAX_TREES_PATH = 8;
            int additionalTrees = (int)Random.Range(0, MAX_TREES_PATH);
            for(int n=0;n<additionalTrees;n++)
            {
                float yTreeOffset = n * (CHUNK_SIZE/MAX_TREES_PATH) + Random.Range(0.0f, (CHUNK_SIZE/MAX_TREES_PATH) * 0.25f) + this.transform.position.z;
                float xTreeOffset = TerrainGenerator.Instance.GetPathCenter(yTreeOffset) * 15.0f + (Random.Range(-1.0f, 1.0f) * 10.0f);
                Vector2 treePos = new Vector2(xTreeOffset, yTreeOffset);
                float height = TerrainGenerator.Instance.GetHeight(treePos.x, treePos.y);

                GameObject g = PoolManager.Instance.GetInstance(TerrainGenerator.Instance.SnowmanObstaclePrefab);
                if(g != null)
                {
                    g.transform.position = new Vector3(treePos.x, height, treePos.y);
                    g.transform.rotation = Quaternion.identity * Quaternion.AngleAxis(180.0f, Vector3.up);
                    localPooledPrefabs.Add(g);
                }
            }

            int MAX_PICKUPITEMS_PATH = 1;
            int pickupItemCount = (Random.Range(0.0f, 1.0f) * 1000.0f) > this.transform.position.z || Random.Range(0.0f, 1.0f) < 0.25f ? MAX_PICKUPITEMS_PATH : 0;
            for(int n=0;n<pickupItemCount;n++)
            {
                float yItemOffset = n * (CHUNK_SIZE/MAX_PICKUPITEMS_PATH) + Random.Range(0.0f, (CHUNK_SIZE/MAX_PICKUPITEMS_PATH) * 0.75f + 0.5f ) + this.transform.position.z;
                float xItemOffset = TerrainGenerator.Instance.GetPathCenter(yItemOffset) * 15.0f + (Random.Range(-1.0f, 1.0f) * 10.0f);
                Vector2 itemPos = new Vector2(xItemOffset, yItemOffset);
                float height = TerrainGenerator.Instance.GetHeight(itemPos.x, itemPos.y);

                GameObject g = PoolManager.Instance.GetInstance(TerrainGenerator.Instance.PickupPrefab);
                if(g != null)
                {
                    g.transform.position = new Vector3(itemPos.x, height, itemPos.y);
                    localPooledPrefabs.Add(g);
                }
            }
        }

        this.UpdateMesh();
    }
}
