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

[System.Serializable]
public class RoomGrid
{
    Vector3Int startingTile;
    Vector2Int size, roomSize;
    public Room[,] grid;
    Tilemap tileMap;

    // Constructor
    public RoomGrid(Vector3Int startingTile, Vector2Int size, Vector2Int roomSize, Tilemap tileMap)
    {
        this.startingTile = startingTile;
        this.size = size;
        this.roomSize = roomSize;
        this.tileMap = tileMap;
        this.grid = new Room[size.x, size.y];
        generateRooms();
    }

    // Generates the rooms of the grid
    void generateRooms()
    {
        for (int x = 0; x < size.x; x++)
        {
            for (int y = 0; y < size.y; y++)
            {
                //Debug.Log("Generating room: " + x + ", " + y);
                grid[x, y] = new Room(new Vector3Int(
                    startingTile.x + x * (roomSize.x + 2),
                    startingTile.y - y * (roomSize.y + 2), 0),
                    roomSize, tileMap);
            }
        }
    }

    // Tells the Rooms to draw their walls
    public void drawRoomWalls()
    {
        for (int x = 0; x < size.x; x++)
        {
            for (int y = 0; y < size.y; y++)
            {
                grid[x, y].drawWalls();
            }
        }
    }

    //Tells the Rooms to draw their centers with the given tile
    public void drawRoomCenter(string tile)
    {
        for (int x = 0; x < size.x; x++)
        {
            for (int y = 0; y < size.y; y++)
            {
                grid[x, y].drawCenter(tile);
            }
        }
    }

    // Generates the path for the grid
    public void generatePath()
    {
        // Resets the rooms' types
        resetRoomTypes();

        // Sets the starting room
        int startingRoom = Random.Range(0, size.x);
        grid[startingRoom, 0].setRoomType(1);

        // Current room
        Vector2Int currentRoom = new Vector2Int(startingRoom,0);
        int currentRoomType = 0;
        Debug.Log(currentRoom.x + ", " + currentRoom.y + " > START");
        int roomCount = 0;

        // false is left, true is right
        bool direction = true;

        // If true, advances, else goes down
        bool advance = false;

        // True when the path finishes
        bool finish = false;

        // Select optimal direction
        if (currentRoom.x < size.x / 2)
        {
            direction = true;
        }
        else direction = false;

        // Room loop until the path finishes
        while (!finish)
        {
            roomCount++;
            Debug.Log("1- Room Count: " + roomCount);

            // Select to advance or go down
            Debug.Log("2- Room: " + currentRoom.x + ", " + currentRoom.y);
            currentRoomType = grid[currentRoom.x, currentRoom.y].getRoomType();
            if (currentRoomType != 1 && currentRoomType != 4)
            {
                if (Random.Range(1, 7) < 5) advance = true;
                else
                {
                    advance = false;
                }
            }
            else
            {
                advance = true;
            }

            Debug.Log("3- Advance: " + advance);
            

            // Advance case
            // Checks if it can advance, otherwise goes down
            if (advance)
            {
                // Go right
                if (direction)
                {
                    // Checks if there's a room to advance
                    if (roomExists(currentRoom.x + 1, currentRoom.y) == true)
                    {
                        Debug.Log("5- > Right");
                        if (currentRoomType != 1 && currentRoomType != 4)
                        {
                            grid[currentRoom.x, currentRoom.y].setRoomType(2);
                        }
                        currentRoom.x++;
                    }
                    else advance = false;
                }
                // Go left
                else
                {
                    if (roomExists(currentRoom.x - 1, currentRoom.y) == true)
                    {
                        Debug.Log("5-  > Left");
                        if (currentRoomType != 1 && currentRoomType != 4)
                        {
                            grid[currentRoom.x, currentRoom.y].setRoomType(2);
                        }
                        currentRoom.x--;
                    }
                    else advance = false;
                }
            }

            // Down case
            if (!advance)
            {
                // If there's a bottom room
                if (roomExists(currentRoom.x, currentRoom.y + 1) == true)
                {
                    Debug.Log("5- > Down");
                    grid[currentRoom.x, currentRoom.y].setRoomType(3);
                    grid[currentRoom.x, currentRoom.y + 1].setRoomType(4);
                    currentRoom.y++;

                    // Select optimal direction
                    if (currentRoom.x < size.x / 2)
                    {
                        direction = true;
                    }
                    else direction = false;
                }
                else
                {
                    Debug.Log(currentRoom.x + ", " + currentRoom.y + " > FINISH");
                    grid[currentRoom.x, currentRoom.y].setRoomType(5);
                    finish = true;
                }
            }
        }
    }

    // Returns true if the given room exists in the grid
    private bool roomExists(int x, int y)
    {
        Debug.Log("4- X-Check: " + x + " > " + size.x);
        Debug.Log("4- Y-Check: " + y + " > " + size.y);
        if (x < 0 || x >= size.x)
        {
            return false;
        }
        if (y < 0 || y >= size.y)
        {
            return false;
        }
        Debug.Log("4.5- Check true: " + y + " > " + size.y);
        return true;
    }

    // draws the path of the grid
    public void drawPath()
    {
        for (int x = 0; x < size.x; x++)
        {
            for (int y = 0; y < size.y; y++)
            {
                if (grid[x, y].getRoomType() == 0) grid[x, y].drawCenter("ground");
                if (grid[x, y].getRoomType() == 1) grid[x, y].drawCenter("green");
                if (grid[x, y].getRoomType() == 2) grid[x, y].drawCenter("highlight");
                if (grid[x, y].getRoomType() == 3) grid[x, y].drawCenter("blue");
                if (grid[x, y].getRoomType() == 4) grid[x, y].drawCenter("blue");
                if (grid[x, y].getRoomType() == 5) grid[x, y].drawCenter("red");
            }
        }

    }
    // Turns all the rooms' types to 0
    public void resetRoomTypes()
    {
        for (int x = 0; x < size.x; x++)
        {
            for (int y = 0; y < size.y; y++)
            {
                grid[x, y].setRoomType(0);
            }
        }
    }
    // Draws null tiles on Rooms' center
    public void drawEmptyCenter()
    {
        for (int x = 0; x < size.x; x++)
        {
            for (int y = 0; y < size.y; y++)
            {
                grid[x, y].drawCenter(null);
            }
        }
    }
    // Draws the rooms
    public void drawRooms()
    {
        for (int x = 0; x < size.x; x++)
        {
            for (int y = 0; y < size.y; y++)
            {
                grid[x, y].drawRoom();
            }
        }
        closeExternalWalls();
    }

    // Closes the exits that lead out of the grid, exluding the start and end
    public void closeExternalWalls()
    {
        for (int x = 0; x < size.x; x++)
        {
            for (int y = 0; y < size.y; y++)
            {
                // Top
                if(y == 0)
                {
                    if(grid[x,y].getRoomType() != 1)
                    {
                        grid[x, y].actionWall(0, true);
                    }
                }
                // Bottom
                if (y == size.y + 1)
                {
                    if (grid[x, y].getRoomType() != 5)
                    {
                        grid[x, y].actionWall(2, true);
                    }
                }
                // Left
                if(x == 0)
                {
                    grid[x, y].actionWall(3, true);
                }
                // Right
                if (x == size.x - 1)
                {
                    grid[x, y].actionWall(1, true);
                }
            }
        }
    }

    public void removeTileMaps()
    {
        foreach (Transform child in tileMap.transform)
        {
            GameObject.Destroy(child.gameObject);
        }
    }
}
