using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Tilemaps;

public class NodeMap : MonoBehaviour
{
    public Vector2Int mapSize;
    public Node[,] nodeGrid = new Node[0,0]; 
    public float cellSize;
    public TileData[] TileDatas;
    public Dictionary<TileBase, TileData> DataFromTiles = new Dictionary<TileBase, TileData>();
    public bool hasEverRun = false;
    public Tilemap tilemap;
    // Start is called before the first frame update


    void Start()
    {
            DataFromTiles = new Dictionary<TileBase, TileData>();
            foreach (var tileData in TileDatas)
            {
                foreach (var tile in tileData.Tiles)
                {
                    DataFromTiles.Add(tile, tileData);
                }
            }
            hasEverRun = true;
            CreateNodes();
            TileCheck();
    }

    public void Generate()
    {
            DataFromTiles = new Dictionary<TileBase, TileData>();
            foreach (var tileData in TileDatas)
            {
                foreach (var tile in tileData.Tiles)
                {
                    DataFromTiles.Add(tile, tileData);
                }
            }
            hasEverRun = true;
            CreateNodes();
            TileCheck();
    }



    public void TileCheck()
    {
        foreach (var n in nodeGrid)
        {
            Vector2Int gridPosition = n.gridPosition;
            
            Vector3Int TileGridPosition = tilemap.WorldToCell(n.worldPosition);
            TileBase Tile = tilemap.GetTile(TileGridPosition);
            if (Tile == null) continue;
            if (!DataFromTiles.ContainsKey(Tile))
            {
                continue;
            }
            n.walkable = DataFromTiles[Tile].walkable;
        }        
    }
    
    // Update is called once per frame
    void Update()
    {

    }

    public void TeleportTo(GameObject g, Node node)
    {
        g.transform.position = node.worldPosition;
    }

    public List<Node> GetNeighbours(Node node)
    {
        List<Node> neighbours = new List<Node>();

        for (int x = -1; x <= 1; x++)
        {
            for (int y = -1; y <= 1; y++)
            {
                if (x == 0 && y == 0)
                    continue;

                int checkX = node.gridPosition.x + x;
                int checkY = node.gridPosition.y + y;

                if (checkX >= 0 && checkX < mapSize.x && checkY >= 0 && checkY < mapSize.y)
                {
                    Node item = nodeGrid[checkX, checkY];
                    neighbours.Add(item);
                }
            }
        }

        return neighbours;
    }

    
    public void CreateNodes()
    {
        nodeGrid = new Node[mapSize.x, mapSize.y];
        for (int x = 0; x < nodeGrid.GetLength(0); x++)
        {
            for (int y = 0; y < nodeGrid.GetLength(1); y++)
            {
                Vector2Int gridPosition = new Vector2Int(x, y);
                nodeGrid[x, y] = new Node(gridPosition, GetWorldPosition(gridPosition));
                Vector3Int TileGridPosition = tilemap.WorldToCell(nodeGrid[x,y].worldPosition);
                TileBase Tile = tilemap.GetTile(TileGridPosition);
                
                //nodeGrid[x, y].walkable = DataFromTiles[Tile].walkable;
                
            }
        }
    }

    public Node NodeFromWorldPoint(Vector2 worldPosition)
    {
        float percentX = (worldPosition.x + mapSize.x / 2) / mapSize.x;
        float percentY = (worldPosition.y + mapSize.y / 2) / mapSize.y;
        percentX = Mathf.Clamp01(percentX);
        percentY = Mathf.Clamp01(percentY);

        int x = Mathf.RoundToInt((mapSize.x - 1) * percentX);
        int y = Mathf.RoundToInt((mapSize.y - 1) * percentY);
        return nodeGrid[x, y];
    }

    
    public Vector3 GetWorldPosition(Vector2Int position)
    {
        Vector3 worldBottomLeft = transform.position - (Vector3.right * (mapSize.x / 2)) - (Vector3.up * (mapSize.y / 2));
        Vector3 worldPoint = worldBottomLeft + (Vector3.right * position.x) + (Vector3.up * position.y);
        Vector3 cellSizeOffset = new Vector3(cellSize / 2, cellSize / 2, 0);
        return worldPoint * cellSize + cellSizeOffset;
    }

    public bool showIndividualNodes;
    
    
    public void OnDrawGizmos()
    {
        Gizmos.DrawWireCube(transform.position,new Vector3(mapSize.x,mapSize.y,1) * cellSize);
        if (!showIndividualNodes)
        {
            return;
        }

        foreach (var n in nodeGrid)
        {
            Vector3 size = Vector3.one * cellSize;
            Gizmos.DrawWireCube(n.worldPosition, size);
        }
    }
}