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

public class WorldGenerator : MonoBehaviour
{
    public GameObject player;
    public GameObject[] prefabs;
    Dictionary<Vector3, GameObject> tiles;
    GameObject currentTile;
    List<GameObject> renderedTiles;
    List<GameObject> toRemove;
    NoiseGenerator noise;
    int cityAmount = 0;
    int maxCityAmount = 0;
    System.Random rand = new System.Random();

    // Start is called before the first frame update
    void Start()
    {
        tiles = new Dictionary<Vector3, GameObject>();
        tiles.Add(new Vector3(0,0,0), GameObject.Find("Spawn"));
        renderedTiles = new List<GameObject>();
        currentTile = GameObject.Find("Spawn");
        currentTile.GetComponent<Tile>().setPosition(new Vector3(0, 0, 0));
        currentTile.GetComponent<Tile>().setBorders();
        renderedTiles.Add(currentTile);
        noise = new NoiseGenerator();
        cityAmount = 10;
        maxCityAmount = 10;
    }

    public bool gameWon()
    {
        return cityAmount <= 0;
    }

    public void resetGame(int cityAmount)
    {
        foreach (GameObject tile in tiles.Values)
        {
            if (tile.name != "Spawn")
            {
                Destroy(tile);
            }
        }
        player.transform.position = new Vector3(0,1.5f,0);
        player.transform.rotation = Quaternion.identity;
        Start();
        currentTile.GetComponent<Tile>().resetSpawn();
        this.cityAmount = cityAmount;
        maxCityAmount = cityAmount;
    }

    // Update is called once per frame
    void Update()
    {
        createTile(player.transform.position.x, player.transform.position.z);
        hideTile(player.transform.position.x, player.transform.position.z);
        resetPlayer();
    }

    public void prepareMap()
    {
        GameObject.Find("Map").GetComponent<Map>().prepare(tiles, currentTile);
    }

    void resetPlayer()
    {
        if (player.transform.position.y <= -5)
        {
            Vector3 position = new Vector3(currentTile.transform.position.x, 5, currentTile.transform.position.z);
            player.transform.SetPositionAndRotation(position, player.transform.rotation);
        }
    }

    public void createTile(float playerX, float playerZ)
    {
        Vector3 pos = currentTile.GetComponent<Tile>().needConnectedTile(playerX, playerZ);
        if (!tiles.ContainsKey(pos) && pos.y == 0)
        {
            int index;
            int chance = rand.Next(1,101);
            
            while (true)
            {
                if (chance < 50)
                {
                    index = 0;
                }
                else if (chance >= 50 && chance < 70)
                {
                    index = 1;
                }
                else if (chance >= 70 && chance < 90)
                {
                    index = 2;
                }
                else
                {
                    index = 3;
                }

                if (index == 3)
                {
                    if (cityAmount > 0)
                    {
                        cityAmount--;
                        break;
                    }
                    else
                    {
                        chance = rand.Next(1, 101);
                    }
                }
                else
                {
                    break;
                }
            }
            Vector3 mapPos = new Vector3(pos.x * 100, 0, pos.z * 100);
            GameObject newTile = Instantiate(prefabs[index], mapPos, Quaternion.identity);
            string name = prefabs[index].name;
            if (name.Contains("_"))
            {
                name = name.Split('_')[0];
            }
            newTile.name = name + "_" + tiles.Count;
            newTile.GetComponent<Tile>().generateTile(pos, name);
            applyNoise(newTile, name.Split('_')[0]);
            tiles.Add(pos, newTile);
            renderedTiles.Add(newTile);
        }
        else
        {
            if (tiles.ContainsKey(pos) && pos.y == 0)
            {
                if (!tiles[pos].GetComponent<Renderer>().enabled)
                {
                    tiles[pos].GetComponent<Tile>().changeRenderer();
                    renderedTiles.Add(tiles[pos]);
                }
            }
        }
    }

    private void applyNoise(GameObject tile, string type)
    {
        switch (type.ToLower())
        {
            case "tile":
                noise.applyTileNoise(tile);
                break;
            case "stonetile":
                noise.applyStoneTileNoise(tile);
                break;
            case "treetile":
                noise.applyTreeTileNoise(tile);
                break;
            case "citytile":
                noise.applyCityTileNoise(tile);
                break;
        }
    }

    public void hideTile(float playerX, float playerZ)
    {
        if (currentTile.GetComponent<Tile>().leftTile(playerX, playerZ))
        {
            renderedTiles.Remove(currentTile);
            foreach (GameObject tile in renderedTiles)
            {
                if (tile.GetComponent<Tile>().enteredTile(playerX, playerZ))
                {
                    currentTile = tile;
                    break;
                }
            }
            updateRenderedTiles();
        }

        if (currentTile.GetComponent<Tile>().removeConnectedTiles(playerX, playerZ))
        {
            updateRenderedTiles();
        }
    }

    private void updateRenderedTiles()
    {
        toRemove = new List<GameObject>();
        foreach (GameObject tile in renderedTiles)
        {
            if (!tile.Equals(currentTile))
            {
                tile.GetComponent<Tile>().changeRenderer();
                toRemove.Add(tile);
            }
        }

        foreach (GameObject tile in toRemove)
        {
            renderedTiles.Remove(tile);
        }
    }

    public GameObject getCurrentTile()
    {
        return currentTile;
    }

    public void updateCityCount(GameObject gameObject)
    {
        gameObject.GetComponent<Text>().text = "Cities: " + (maxCityAmount - cityAmount) + "/" + maxCityAmount;
    }
}
