using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
using UnityEngine.Tilemaps;
using UnityEngine.UIElements;

public class MapGenerator : MonoBehaviour
{
    public Tilemap tileMap;
    public TileBase waterPrefab;
    public TileBase grassPrefab;
    public TileBase sandPrefab;
    public TileBase forestPrefab;
    public TileBase mountainPrefab;

    public GameObject player;

    public int width;
    public int height;
    public int[,] map;
    float[,] noiseMap;
    float noiseValue;

    [Range(0, 100)]
    public int randomFillPercentage;

    public float seed;
    public bool useRandomSeed;
    public float scale;

    private void Start()
    {
        GenerateMap();
    }

    void Update() {
        if (Input.GetMouseButtonDown(0)) {
            GenerateMap();
        }
    }
    void GenerateMap() {
        map = new int[height, width];
        proceduralGen();

        for (int i = 0; i < 5; i++) {
            SmoothMap();
        }
        AddTerrainTypes();
        DrawTiles();
    }
    void proceduralGen() {
        noiseMap = new float[height, width];
        // Generating random float value to use as seed
        float randomFloat = UnityEngine.Random.Range(0, 10000000f);

        // Checking if useRandomSeed Boolean is true in the inspector
        if (useRandomSeed) {
            seed = randomFloat;
        }
        System.Random pseudoRandom = new System.Random((int)seed);

        // Offset to add to Perlin noise
        float offsetX = randomFloat + 100f;
        float offsetY = randomFloat + 200f;

        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                float xCoord = (float)x / width * scale + offsetX;
                float yCoord = (float)y / height * scale + offsetY;
                noiseMap[x, y] = Mathf.PerlinNoise(xCoord, yCoord);

                // Add randomization to the Perlin noise
                float randomValue = (float)pseudoRandom.NextDouble() * 2f - 1f;
                noiseValue += randomValue * 0.1f;

                // Edge of the map is water
                if (x == 0 || x == width - 1 || y == 0 || y == height - 1) {
                    map[x, y] = 0;

                } else {
                    map[x, y] = (pseudoRandom.Next(0, 100) < randomFillPercentage) ? 0 : 1;
                }
            }
        }

    }
    void AddTerrainTypes()
    {
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {

                if (map[x, y] == 0)
                {
                    int terrainType;
                    noiseValue = noiseMap[x, y];

                    if (noiseValue < 0.1f)
                    {
                        terrainType = 2; // Mountains
                    }
                    else if (noiseValue < 0.4f)
                    {
                        terrainType = 3; // Forests
                    }
                    else
                    {
                        terrainType = 4; // savanna
                    }
                    // Add random variations to terrain types
                    switch (terrainType)
                    {
                        case 2: // Mountains
                            map[x, y] = 2;
                            break;
                        case 3: // Forests
                            map[x, y] = 3;
                            break;
                        case 4: // Savanna
                            map[x, y] = 4;
                            break;
                        default: // Water
                            map[x, y] = 1;
                            break;
                    }
                }
            }
        }
    }

    void DrawTiles()
    {
        if (map != null)
        {
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    Vector3Int pos = new Vector3Int(-width / 2 + x, -height / 2 + y, 0);
                    tileMap.SetTile(pos, map[x, y] == 1 ? grassPrefab : waterPrefab);

                    switch (map[x, y])
                    {
                        case 2:
                            tileMap.SetTile(pos, mountainPrefab);
                           break;
                        case 3:
                            tileMap.SetTile(pos, forestPrefab);
                            break;
                        case 4:
                            tileMap.SetTile(pos, sandPrefab);
                            break;
                        default:
                            tileMap.SetTile(pos, waterPrefab);
                            break;
                    }
                }
            }
        }
    }

    void SmoothMap() {
        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                int neighbourWallTile = GetSurroundingWallCount(x, y);

                if (neighbourWallTile > 4) {
                    map[x, y] = 1;
                } else if (neighbourWallTile < 4) {
                    map[x, y] = 0;
                }

            }
        }
    }
    int GetSurroundingWallCount(int gridX, int gridY)
    {
        int wallCount = 0;
        for (int neighbourX = gridX - 1; neighbourX <= gridX + 1; neighbourX++) {
            for (int neighbourY = gridY - 1; neighbourY <= gridY + 1; neighbourY++) {
                if (neighbourX >= 0 && neighbourX < width && neighbourY >= 0 && neighbourY < height) {
                    if (neighbourX != gridX || neighbourY != gridY) {
                        wallCount += map[neighbourX, neighbourY];
                    }
                } else {
                    wallCount++;
                }
            }
        }

        return wallCount;
    }

}