using UnityEngine;
using System.Collections.Generic;

public class RiverGenerator
{
    public void GenerateRivers(MapData mapData)
    {
        // Find water bodies to connect
        var waterBodies = FindWaterBodies(mapData);

        Debug.Log($"Found {waterBodies.Count} water body tiles for river generation");

        // Generate fewer, thinner rivers between some water bodies
        int riverCount = Mathf.Min(3, waterBodies.Count - 1); // Maximum 3 rivers
        riverCount = Mathf.Max(1, riverCount); // Force at least 1 river if possible

        Debug.Log($"Attempting to generate {riverCount} rivers");

        for (int i = 0; i < riverCount && i < waterBodies.Count - 1; i++)
        {
            CreateRiver(mapData, waterBodies[i], waterBodies[i + 1]);
            Debug.Log($"Created river {i + 1} from {waterBodies[i]} to {waterBodies[i + 1]}");
        }
    }
    private List<Vector2Int> FindWaterBodies(MapData mapData)
    {
        List<Vector2Int> waterBodyCenters = new List<Vector2Int>();
        bool[,] visited = new bool[mapData.Width, mapData.Height];

        // Find distinct water bodies (groups of connected water tiles)
        for (int x = 0; x < mapData.Width; x++)
        {
            for (int y = 0; y < mapData.Height; y++)
            {
                MapTile tile = mapData.GetTile(x, y);
                if (!visited[x, y] && (tile.terrainType == TerrainType.Ocean || tile.terrainType == TerrainType.Lake))
                {
                    // Found a new water body, find its center
                    var waterTiles = FloodFillWaterBody(mapData, visited, x, y);
                    if (waterTiles.Count > 5) // Only consider substantial water bodies
                    {
                        Vector2Int center = CalculateCenter(waterTiles);
                        waterBodyCenters.Add(center);
                        Debug.Log($"Found water body center at {center} with {waterTiles.Count} tiles");
                    }
                }
            }
        }

        return waterBodyCenters;
    }

    private List<Vector2Int> FloodFillWaterBody(MapData mapData, bool[,] visited, int startX, int startY)
    {
        List<Vector2Int> waterTiles = new List<Vector2Int>();
        Queue<Vector2Int> queue = new Queue<Vector2Int>();
        queue.Enqueue(new Vector2Int(startX, startY));

        while (queue.Count > 0)
        {
            Vector2Int current = queue.Dequeue();
            if (visited[current.x, current.y]) continue;

            visited[current.x, current.y] = true;
            waterTiles.Add(current);

            // Check neighbors
            for (int dx = -1; dx <= 1; dx++)
            {
                for (int dy = -1; dy <= 1; dy++)
                {
                    if (dx == 0 && dy == 0) continue;

                    int newX = current.x + dx;
                    int newY = current.y + dy;

                    if (mapData.IsValidPosition(newX, newY) && !visited[newX, newY])
                    {
                        MapTile tile = mapData.GetTile(newX, newY);
                        if (tile.terrainType == TerrainType.Ocean || tile.terrainType == TerrainType.Lake)
                        {
                            queue.Enqueue(new Vector2Int(newX, newY));
                        }
                    }
                }
            }
        }

        return waterTiles;
    }

    private Vector2Int CalculateCenter(List<Vector2Int> tiles)
    {
        if (tiles.Count == 0) return Vector2Int.zero;

        float avgX = 0f;
        float avgY = 0f;

        foreach (var tile in tiles)
        {
            avgX += tile.x;
            avgY += tile.y;
        }

        return new Vector2Int(Mathf.RoundToInt(avgX / tiles.Count), Mathf.RoundToInt(avgY / tiles.Count));
    }

    private void CreateRiver(MapData mapData, Vector2Int start, Vector2Int end)
    {
        var riverPath = FindRiverPath(mapData, start, end);

        foreach (var point in riverPath)
        {
            if (mapData.IsValidPosition(point.x, point.y))
            {
                MapTile tile = mapData.GetTile(point.x, point.y);
                if (tile.terrainType == TerrainType.Plains || tile.terrainType == TerrainType.Shore)
                {
                    tile.terrainType = TerrainType.River;
                    tile.isWalkable = false;
                }
            }
        }

        // Smart diagonal blocking - only fill specific diagonal gaps
        BlockDiagonalCrossings(mapData, riverPath);
    }

    private void BlockDiagonalCrossings(MapData mapData, List<Vector2Int> riverPath)
    {
        foreach (var riverPoint in riverPath)
        {
            // Check for diagonal gaps that would allow diagonal crossing
            for (int dx = -1; dx <= 1; dx += 2) // -1 and 1
            {
                for (int dy = -1; dy <= 1; dy += 2) // -1 and 1
                {
                    Vector2Int diagonal = new Vector2Int(riverPoint.x + dx, riverPoint.y + dy);
                    Vector2Int horizontal = new Vector2Int(riverPoint.x + dx, riverPoint.y);
                    Vector2Int vertical = new Vector2Int(riverPoint.x, riverPoint.y + dy);

                    if (mapData.IsValidPosition(diagonal.x, diagonal.y) &&
                        mapData.IsValidPosition(horizontal.x, horizontal.y) &&
                        mapData.IsValidPosition(vertical.x, vertical.y))
                    {
                        // If diagonal tile is river and both adjacent tiles are not river,
                        // there's a crossable diagonal gap
                        if (mapData.GetTile(diagonal.x, diagonal.y).terrainType == TerrainType.River &&
                            mapData.GetTile(horizontal.x, horizontal.y).terrainType != TerrainType.River &&
                            mapData.GetTile(vertical.x, vertical.y).terrainType != TerrainType.River)
                        {
                            // Fill one of the adjacent tiles to block diagonal crossing
                            MapTile fillTile = mapData.GetTile(horizontal.x, horizontal.y);
                            if (fillTile.terrainType == TerrainType.Plains || fillTile.terrainType == TerrainType.Shore)
                            {
                                fillTile.terrainType = TerrainType.River;
                                fillTile.isWalkable = false;
                            }
                        }
                    }
                }
            }
        }
    }
    private List<Vector2Int> FindRiverPath(MapData mapData, Vector2Int start, Vector2Int end)
    {
        List<Vector2Int> path = new List<Vector2Int>();
        Vector2Int current = start;

        while (Vector2Int.Distance(current, end) > 1)
        {
            path.Add(current);

            // Move towards end with some meandering
            Vector2Int direction = new Vector2Int(
                end.x > current.x ? 1 : (end.x < current.x ? -1 : 0),
                end.y > current.y ? 1 : (end.y < current.y ? -1 : 0)
            );

            // Add meandering
            if (Random.value < 0.4f)
            {
                direction.x += Random.Range(-1, 2);
                direction.y += Random.Range(-1, 2);
                direction.x = Mathf.Clamp(direction.x, -1, 1);
                direction.y = Mathf.Clamp(direction.y, -1, 1);
            }

            Vector2Int next = current + direction;
            if (mapData.IsValidPosition(next.x, next.y))
            {
                current = next;
            }
            else
            {
                break;
            }
        }

        return path;
    }

    private void FillRiverDiagonals(MapData mapData, int x, int y)
    {
        // Check and fill diagonal gaps to prevent crossing without a bridge
        for (int dx = -1; dx <= 1; dx++)
        {
            for (int dy = -1; dy <= 1; dy++)
            {
                if (dx == 0 || dy == 0) continue; // Skip cardinal directions

                int checkX = x + dx;
                int checkY = y + dy;

                if (mapData.IsValidPosition(checkX, checkY))
                {
                    MapTile neighbor = mapData.GetTile(checkX, checkY);
                    if (neighbor.terrainType == TerrainType.River)
                    {
                        // Fill the gap
                        int fillX = x + (dx > 0 ? 1 : 0);
                        int fillY = y + (dy > 0 ? 1 : 0);

                        if (mapData.IsValidPosition(fillX, fillY))
                        {
                            MapTile fillTile = mapData.GetTile(fillX, fillY);
                            if (fillTile.terrainType == TerrainType.Plains)
                            {
                                fillTile.terrainType = TerrainType.River;
                                fillTile.isWalkable = false;
                            }
                        }
                    }
                }
            }
        }
    }
}