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

/// <summary>
/// Manages map exploration using a pre-generated large map with fog of war
/// </summary>
public class ExplorationManager
{
    private MapMaker2 mapMaker;
    private MapData fullMapData; // The complete pre-generated map
    private bool[,] exploredMask; // Tracks which areas have been revealed
    private float lastExplorationTime = 0f; // Cooldown tracking

    // Performance settings for large maps
    private bool performanceMode = false; // Enable for maps larger than 200x200
    private int lodLevel = 1; // Level of Detail: 1 = full detail, 2 = half detail, 4 = quarter detail

    // Exploration Settings - Public properties for MapMaker2 to set
    public int fullMapWidth { get; set; } = 300;
    public int fullMapHeight { get; set; } = 300;
    public int initialVisibleSize { get; set; } = 80; // Starting visible area
    public int explorationChunkSize { get; set; } = 40; // Size of chunks to reveal
    public float explorationDistance { get; set; } = 10f; // Distance from edge to trigger exploration (reduced from 20f)
    public float explorationCooldown { get; set; } = 3f; // Cooldown between explorations

    public ExplorationManager(MapMaker2 mapMaker)
    {
        this.mapMaker = mapMaker;
    }

    /// <summary>
    /// Initialize the exploration system with a large pre-generated map
    /// </summary>
    public void InitializeExploration()
    {
        Debug.Log("🗺️ Initializing Exploration System...");

        // Check if we need performance mode for large maps
        if (fullMapWidth > 200 || fullMapHeight > 200)
        {
            performanceMode = true;
            lodLevel = CalculateOptimalLOD(fullMapWidth, fullMapHeight);
            Debug.Log($"⚡ Performance mode enabled with LOD level {lodLevel} for large map");
        }

        // Generate the full large map
        GenerateFullMap();

        // Initialize exploration mask
        exploredMask = new bool[fullMapWidth, fullMapHeight];
        Debug.Log($"🔍 Created exploration mask: {fullMapWidth}x{fullMapHeight}");

        // Reveal initial area around the center
        RevealInitialArea();

        // Update the visible map data
        UpdateVisibleMap();

        Debug.Log($"✅ Exploration System initialized - Full map: {fullMapWidth}x{fullMapHeight}, Initial visible: {initialVisibleSize}x{initialVisibleSize}");
    }

    /// <summary>
    /// Calculate optimal Level of Detail for given map size
    /// </summary>
    private int CalculateOptimalLOD(int width, int height)
    {
        int totalTiles = width * height;

        if (totalTiles > 250000) // 500x500+
            return 4; // Quarter detail
        else if (totalTiles > 100000) // 316x316+
            return 2; // Half detail
        else
            return 1; // Full detail
    }

    /// <summary>
    /// DEBUG: Show the entire 300x300 map for testing purposes
    /// </summary>
    public void ShowFullMap()
    {
        if (fullMapData == null)
        {
            Debug.LogError("❌ Full map data not available!");
            return;
        }

        Debug.Log("🌍 Loading full 300x300 map for debugging...");

        // Get the current position in full map coordinates BEFORE switching to full map
        Vector2Int currentFullMapPosition = GetCurrentTeamPositionInFullMapImproved();
        Debug.Log($"🎯 Team position before full map: Full map coordinates ({currentFullMapPosition})");

        // Mark entire map as explored
        for (int x = 0; x < fullMapWidth; x++)
        {
            for (int y = 0; y < fullMapHeight; y++)
            {
                exploredMask[x, y] = true;
            }
        }

        // Update the visible map to show everything
        UpdateVisibleMap();

        // Restore team marker to the correct full map position
        RestoreTeamMarkerToFullMapPosition(currentFullMapPosition);

        Debug.Log($"✅ Full map is now visible!");
    }

    /// <summary>
    /// TEST: Debug coordinate conversion to find the issue
    /// </summary>
    public void TestCoordinateConversion()
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null)
        {
            Debug.LogError("❌ SimpleTeamPlacement not found!");
            return;
        }

        GameObject teamMarker = GameObject.Find("TeamMarker");
        if (teamMarker == null)
        {
            Debug.LogError("❌ TeamMarker not found!");
            return;
        }

        // Get current state
        Vector3 worldPos = teamMarker.transform.position;
        Vector2Int storedPos = teamPlacement.GetCurrentTeamPosition();
        Rect exploredBounds = GetExploredBounds();
        bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5;

        Debug.Log("=== COORDINATE CONVERSION TEST ===");
        Debug.Log($"Team Marker World Position: ({worldPos.x:F1}, {worldPos.z:F1})");
        Debug.Log($"Team Placement Stored Position: ({storedPos.x}, {storedPos.y})");
        Debug.Log($"Explored Bounds: {exploredBounds}");
        Debug.Log($"Is Showing Full Map: {isShowingFullMap}");
        Debug.Log($"Full Map Size: {fullMapWidth}x{fullMapHeight}");

        // Test the conversion
        Vector2Int convertedPos = GetCurrentTeamPositionInFullMapImproved();
        Debug.Log($"Converted Full Map Position: ({convertedPos.x}, {convertedPos.y})");

        // Expected position for center of map
        Vector2Int expectedCenter = new Vector2Int(fullMapWidth / 2, fullMapHeight / 2);
        Debug.Log($"Expected Map Center: ({expectedCenter.x}, {expectedCenter.y})");

        // Check if the stored position makes sense
        if (!isShowingFullMap)
        {
            Vector2Int expectedFullMapPos = new Vector2Int(
                (int)exploredBounds.x + storedPos.x,
                (int)exploredBounds.y + storedPos.y
            );
            Debug.Log($"Expected Full Map Pos from Stored: Bounds({exploredBounds.x}, {exploredBounds.y}) + Stored({storedPos.x}, {storedPos.y}) = ({expectedFullMapPos.x}, {expectedFullMapPos.y})");
        }

        Debug.Log("=====================================");
    }

    /// <summary>
    /// TEST: Simple coordinate conversion test
    /// </summary>
    public void TestSimpleCoordinateConversion()
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null)
        {
            Debug.LogError("❌ SimpleTeamPlacement not found!");
            return;
        }

        Vector2Int storedPos = teamPlacement.GetCurrentTeamPosition();
        Rect exploredBounds = GetExploredBounds();

        Debug.Log("=== SIMPLE COORDINATE TEST ===");
        Debug.Log($"Stored team position: ({storedPos.x}, {storedPos.y})");
        Debug.Log($"Explored bounds: {exploredBounds}");

        // Expected full map position
        Vector2Int expectedFullMapPos = new Vector2Int(
            (int)exploredBounds.x + storedPos.x,
            (int)exploredBounds.y + storedPos.y
        );
        Debug.Log($"Expected full map position: ({expectedFullMapPos.x}, {expectedFullMapPos.y})");
        Debug.Log($"Map center: ({fullMapWidth / 2}, {fullMapHeight / 2})");

        bool isNearCenter = Vector2Int.Distance(expectedFullMapPos, new Vector2Int(fullMapWidth / 2, fullMapHeight / 2)) < 10;
        Debug.Log($"Is near map center: {(isNearCenter ? "✅ YES" : "❌ NO")}");

        Debug.Log("===============================");
    }

    /// <summary>
    /// DEBUG: Test positioning after camera and tile fixes
    /// </summary>
    public void TestPositioningAfterFix()
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null)
        {
            Debug.LogError("❌ SimpleTeamPlacement not found!");
            return;
        }

        GameObject teamMarker = GameObject.Find("TeamMarker");
        if (teamMarker == null)
        {
            Debug.LogError("❌ TeamMarker not found!");
            return;
        }

        Vector2Int storedPos = teamPlacement.GetCurrentTeamPosition();
        Rect exploredBounds = GetExploredBounds();
        Vector3 teamMarkerWorldPos = teamMarker.transform.position;

        Debug.Log("=== POSITIONING TEST AFTER FIX ===");
        Debug.Log($"📍 Team Marker World Position: ({teamMarkerWorldPos.x:F1}, {teamMarkerWorldPos.z:F1})");
        Debug.Log($"🗂️ Stored Team Position: ({storedPos.x}, {storedPos.y})");
        Debug.Log($"🗺️ Explored Bounds: {exploredBounds}");

        // Calculate expected world position for the center tile
        Vector3 expectedCenterTileWorldPos = new Vector3(
            (exploredBounds.x + exploredBounds.width / 2f),
            0,
            (exploredBounds.y + exploredBounds.height / 2f)
        );
        Debug.Log($"🎯 Expected Center Tile World Position: ({expectedCenterTileWorldPos.x:F1}, {expectedCenterTileWorldPos.z:F1})");

        // Check camera position
        Camera mainCam = Camera.main;
        if (mainCam != null)
        {
            Debug.Log($"📹 Camera Position: ({mainCam.transform.position.x:F1}, {mainCam.transform.position.y:F1})");
            Debug.Log($"📹 Camera Size: {mainCam.orthographicSize:F1}");
        }

        // Check if team marker should be visible
        float distanceFromExpectedCenter = Vector3.Distance(teamMarkerWorldPos, expectedCenterTileWorldPos);
        Debug.Log($"📏 Distance from expected center: {distanceFromExpectedCenter:F1}");

        bool shouldBeVisible = distanceFromExpectedCenter < 40f; // Within 40 units of center
        Debug.Log($"👁️ Should be visible: {(shouldBeVisible ? "✅ YES" : "❌ NO")}");

        Debug.Log("===================================");
    }

    /// <summary>
    /// DEBUG: Test full map tile coverage to find missing quadrants
    /// </summary>
    public void TestFullMapTileCoverage()
    {
        Debug.Log("=== FULL MAP TILE COVERAGE TEST ===");

        // Get current map data from MapMaker2
        var currentMapData = mapMaker?.GetMapData();
        if (currentMapData == null)
        {
            Debug.LogError("❌ No current map data available!");
            return;
        }

        Debug.Log($"📊 Current Map Data Size: {currentMapData.Width}x{currentMapData.Height}");

        // Check if we're showing full map
        Rect exploredBounds = GetExploredBounds();
        bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5;
        Debug.Log($"🗺️ Is Showing Full Map: {isShowingFullMap}");
        Debug.Log($"🗺️ Explored Bounds: {exploredBounds}");
        Debug.Log($"🗺️ Full Map Size: {fullMapWidth}x{fullMapHeight}");

        if (isShowingFullMap)
        {
            // Test if we have tiles in each quadrant
            int centerX = currentMapData.Width / 2;
            int centerY = currentMapData.Height / 2;

            // Test each quadrant
            Vector2Int[] testPoints = {
                new Vector2Int(centerX / 2, centerY / 2),           // Lower-left
                new Vector2Int(centerX + centerX / 2, centerY / 2), // Lower-right
                new Vector2Int(centerX / 2, centerY + centerY / 2), // Upper-left
                new Vector2Int(centerX + centerX / 2, centerY + centerY / 2) // Upper-right
            };

            string[] quadrantNames = { "Lower-Left", "Lower-Right", "Upper-Left", "Upper-Right" };

            for (int i = 0; i < testPoints.Length; i++)
            {
                var testPoint = testPoints[i];
                var tile = currentMapData.GetTile(testPoint.x, testPoint.y);
                bool hasValidTile = tile != null;

                Debug.Log($"🔍 {quadrantNames[i]} Quadrant ({testPoint.x}, {testPoint.y}): {(hasValidTile ? "✅ HAS TILE" : "❌ NO TILE")}");
                if (hasValidTile)
                {
                    Debug.Log($"   Terrain: {tile.terrainType}, Feature: {tile.featureType}");
                }
            }

            // Test specific areas that might be missing
            Debug.Log("🔍 Testing specific problematic areas:");
            Vector2Int[] problematicPoints = {
                new Vector2Int(0, 0),                    // Bottom-left corner
                new Vector2Int(currentMapData.Width-1, 0),     // Bottom-right corner
                new Vector2Int(0, currentMapData.Height-1),    // Top-left corner
                new Vector2Int(currentMapData.Width-1, currentMapData.Height-1) // Top-right corner
            };

            for (int i = 0; i < problematicPoints.Length; i++)
            {
                var testPoint = problematicPoints[i];
                var tile = currentMapData.GetTile(testPoint.x, testPoint.y);
                bool hasValidTile = tile != null;
                Debug.Log($"🔍 Corner ({testPoint.x}, {testPoint.y}): {(hasValidTile ? "✅ HAS TILE" : "❌ NO TILE")}");
            }
        }
        else
        {
            Debug.Log("⚠️ Not currently showing full map - switch to full map first to test coverage");
        }

        Debug.Log("=====================================");
    }

    /// <summary>
    /// DEBUG: Test visual tile rendering to find missing areas
    /// </summary>
    public void TestVisualTileRendering()
    {
        Debug.Log("=== VISUAL TILE RENDERING TEST ===");

        // Check if we're showing full map
        Rect exploredBounds = GetExploredBounds();
        bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5;
        Debug.Log($"🗺️ Is Showing Full Map: {isShowingFullMap}");
        Debug.Log($"🗺️ Explored Bounds: {exploredBounds}");

        if (isShowingFullMap)
        {
            // Check for actual GameObjects in each quadrant
            string[] quadrantNames = { "Lower-Left", "Lower-Right", "Upper-Left", "Upper-Right" };
            Vector2Int[] testPoints = {
                new Vector2Int(75, 75),           // Lower-left
                new Vector2Int(225, 75),          // Lower-right  
                new Vector2Int(75, 225),          // Upper-left
                new Vector2Int(225, 225)          // Upper-right
            };

            for (int i = 0; i < testPoints.Length; i++)
            {
                var testPoint = testPoints[i];

                // Look for actual tile GameObjects at these world positions
                string terrainTileName = $"TerrainTile_{testPoint.x}_{testPoint.y}";
                GameObject terrainTile = GameObject.Find(terrainTileName);

                string featureTileName = $"FeatureTile_{testPoint.x}_{testPoint.y}";
                GameObject featureTile = GameObject.Find(featureTileName);

                Debug.Log($"🎮 {quadrantNames[i]} Quadrant ({testPoint.x}, {testPoint.y}):");
                Debug.Log($"   Terrain GameObject: {(terrainTile != null ? "✅ EXISTS" : "❌ MISSING")}");
                Debug.Log($"   Feature GameObject: {(featureTile != null ? "✅ EXISTS" : "❌ MISSING")}");

                if (terrainTile != null)
                {
                    Debug.Log($"   Terrain Position: ({terrainTile.transform.position.x:F1}, {terrainTile.transform.position.y:F1})");
                    Debug.Log($"   Terrain Active: {terrainTile.activeInHierarchy}");
                }
            }

            // Check corner tiles specifically
            Debug.Log("🔍 Testing corner tile GameObjects:");
            Vector2Int[] corners = {
                new Vector2Int(0, 0),        // Bottom-left corner
                new Vector2Int(299, 0),      // Bottom-right corner  
                new Vector2Int(0, 299),      // Top-left corner
                new Vector2Int(299, 299)     // Top-right corner
            };

            string[] cornerNames = { "Bottom-Left", "Bottom-Right", "Top-Left", "Top-Right" };

            for (int i = 0; i < corners.Length; i++)
            {
                var corner = corners[i];
                string tileName = $"TerrainTile_{corner.x}_{corner.y}";
                GameObject tile = GameObject.Find(tileName);

                Debug.Log($"🎮 {cornerNames[i]} Corner ({corner.x}, {corner.y}): {(tile != null ? "✅ EXISTS" : "❌ MISSING")}");
                if (tile != null)
                {
                    Debug.Log($"   Position: ({tile.transform.position.x:F1}, {tile.transform.position.y:F1})");
                    Debug.Log($"   Active: {tile.activeInHierarchy}");
                }
            }

            // Count total rendered tiles  
            var allObjects = Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
            var terrainTiles = allObjects.Where(go => go.name.StartsWith("TerrainTile_")).ToArray();
            Debug.Log($"📊 Total rendered terrain tiles: {terrainTiles.Length}");
            Debug.Log($"📊 Expected tiles for 300x300: {300 * 300}");

            if (terrainTiles.Length < 300 * 300)
            {
                Debug.Log($"⚠️ Missing {(300 * 300) - terrainTiles.Length} tiles!");

                // Sample some missing tile names
                for (int y = 0; y < 10; y++)
                {
                    for (int x = 0; x < 10; x++)
                    {
                        string tileName = $"TerrainTile_{x}_{y}";
                        if (GameObject.Find(tileName) == null)
                        {
                            Debug.Log($"   Missing: {tileName}");
                        }
                    }
                }
            }
        }
        else
        {
            Debug.Log("⚠️ Not currently showing full map - switch to full map first");
        }

        Debug.Log("===================================");
    }

    /// <summary>
    /// Restore team marker to correct position in full map coordinates
    /// </summary>
    private void RestoreTeamMarkerToFullMapPosition(Vector2Int fullMapPosition)
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return;

        // In full map mode, full map coordinates = visible coordinates
        Debug.Log($"🔧 Restoring team marker to full map position: ({fullMapPosition})");

        // Update team marker position
        teamPlacement.UpdateMarkerAfterMapChange(fullMapPosition);
    }

    /// <summary>
    /// Get current team marker position in full map coordinates (improved version)
    /// </summary>
    private Vector2Int GetCurrentTeamPositionInFullMapImproved()
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return new Vector2Int(fullMapWidth / 2, fullMapHeight / 2);

        // Instead of reading world position, use the stored position and convert it properly
        Vector2Int storedPosition = teamPlacement.GetCurrentTeamPosition();

        // Check if we're currently showing the full map or a partial exploration view
        Rect exploredBounds = GetExploredBounds();
        bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5;

        Vector2Int fullMapPos;
        if (isShowingFullMap)
        {
            // If already showing full map, stored position = full map coordinates
            fullMapPos = storedPosition;
            Debug.Log($"🎯 Current team position (Full Map): Stored({storedPosition}) = FullMap({fullMapPos})");
        }
        else
        {
            // If showing partial exploration view, convert exploration coordinates to full map coordinates
            fullMapPos = new Vector2Int(
                (int)exploredBounds.x + storedPosition.x,
                (int)exploredBounds.y + storedPosition.y
            );
            Debug.Log($"🎯 Current team position (Exploration): Stored({storedPosition}) + Bounds({exploredBounds.x}, {exploredBounds.y}) → FullMap({fullMapPos})");
            Debug.Log($"🔍 DEBUG: ExploredBounds = {exploredBounds}, IsFullMap = {isShowingFullMap}");
        }

        return fullMapPos;
    }

    /// <summary>
    /// Restore team marker to correct position after map view changes
    /// </summary>
    private void RestoreTeamMarkerPosition(Vector2Int fullMapPosition)
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return;

        // Check if we're currently showing the full map
        Rect exploredBounds = GetExploredBounds();
        bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5;

        Vector2Int visiblePosition;

        if (isShowingFullMap)
        {
            // If showing full map, full map coordinates = visible coordinates
            visiblePosition = fullMapPosition;
            Debug.Log($"🔧 Restored team marker (Full Map): FullMap({fullMapPosition}) → Visible({visiblePosition})");
        }
        else if (performanceMode)
        {
            // Account for LOD scaling in exploration mode
            visiblePosition = new Vector2Int(
                (fullMapPosition.x - (int)exploredBounds.x) / lodLevel,
                (fullMapPosition.y - (int)exploredBounds.y) / lodLevel
            );

            int visibleWidth = (int)exploredBounds.width / lodLevel;
            int visibleHeight = (int)exploredBounds.height / lodLevel;

            visiblePosition.x = Mathf.Clamp(visiblePosition.x, 0, visibleWidth - 1);
            visiblePosition.y = Mathf.Clamp(visiblePosition.y, 0, visibleHeight - 1);

            Debug.Log($"🔧 Restored team marker (Exploration LOD): FullMap({fullMapPosition}) → Visible({visiblePosition}) [LOD:{lodLevel}]");
        }
        else
        {
            // Standard coordinate conversion for exploration mode
            visiblePosition = new Vector2Int(
                fullMapPosition.x - (int)exploredBounds.x,
                fullMapPosition.y - (int)exploredBounds.y
            );

            int visibleWidth = (int)exploredBounds.width;
            int visibleHeight = (int)exploredBounds.height;

            visiblePosition.x = Mathf.Clamp(visiblePosition.x, 0, visibleWidth - 1);
            visiblePosition.y = Mathf.Clamp(visiblePosition.y, 0, visibleHeight - 1);

            Debug.Log($"🔧 Restored team marker (Exploration): FullMap({fullMapPosition}) → Visible({visiblePosition})");
        }

        // Update team marker position
        teamPlacement.UpdateMarkerAfterMapChange(visiblePosition);
    }

    /// <summary>
    /// Toggle performance mode for testing different map sizes
    /// </summary>
    public void TogglePerformanceMode()
    {
        performanceMode = !performanceMode;

        if (performanceMode)
        {
            lodLevel = CalculateOptimalLOD(fullMapWidth, fullMapHeight);
            Debug.Log($"⚡ Performance mode enabled with LOD {lodLevel}");
        }
        else
        {
            lodLevel = 1;
            Debug.Log("🎯 Performance mode disabled - using full detail");
        }

        // Refresh the visible map
        UpdateVisibleMap();
    }

    /// <summary>
    /// Set custom map size for scalability testing
    /// </summary>
    public void SetMapSize(int width, int height)
    {
        fullMapWidth = width;
        fullMapHeight = height;

        // Auto-enable performance mode for large maps
        if (width > 200 || height > 200)
        {
            performanceMode = true;
            lodLevel = CalculateOptimalLOD(width, height);
            Debug.Log($"⚡ Auto-enabled performance mode for {width}x{height} map (LOD {lodLevel})");
        }
        else
        {
            performanceMode = false;
            lodLevel = 1;
            Debug.Log($"🎯 Standard mode for {width}x{height} map");
        }
    }

    /// <summary>
    /// Convert world coordinates to exploration-system-aware tile coordinates
    /// This handles the coordinate system differences between journey and exploration systems
    /// </summary>
    public Vector2Int ConvertWorldToExplorationCoordinates(Vector3 worldPosition)
    {
        // Convert world position to base tile coordinates
        Vector2Int baseTilePos = new Vector2Int(
            Mathf.RoundToInt(worldPosition.x),
            Mathf.RoundToInt(worldPosition.z)  // Use Z for map Y coordinate
        );

        // Get current exploration bounds to determine coordinate system
        Rect exploredBounds = GetExploredBounds();

        // Check if we're showing the full map (when bounds = full map size)
        bool isShowingFullMap = (exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5);

        if (isShowingFullMap)
        {
            // When showing full map, world coordinates ARE the exploration coordinates
            // Just apply LOD scaling if needed
            Vector2Int explorationCoords = baseTilePos;

            if (performanceMode && lodLevel > 1)
            {
                explorationCoords.x = explorationCoords.x / lodLevel;
                explorationCoords.y = explorationCoords.y / lodLevel;

                // Clamp to LOD-scaled bounds
                int lodWidth = (int)exploredBounds.width / lodLevel;
                int lodHeight = (int)exploredBounds.height / lodLevel;
                explorationCoords.x = Mathf.Clamp(explorationCoords.x, 0, lodWidth - 1);
                explorationCoords.y = Mathf.Clamp(explorationCoords.y, 0, lodHeight - 1);
            }
            else
            {
                // Clamp to full map bounds
                explorationCoords.x = Mathf.Clamp(explorationCoords.x, 0, (int)exploredBounds.width - 1);
                explorationCoords.y = Mathf.Clamp(explorationCoords.y, 0, (int)exploredBounds.height - 1);
            }

            Debug.Log($"🌍 FULL MAP: World({worldPosition.x:F1}, {worldPosition.z:F1}) → Exploration({explorationCoords}) [LOD:{lodLevel}]");
            return explorationCoords;
        }
        else
        {
            // Normal exploration mode - convert to relative coordinates within visible area
            Vector2Int explorationCoords = new Vector2Int(
                baseTilePos.x - (int)exploredBounds.x,
                baseTilePos.y - (int)exploredBounds.y
            );

            if (performanceMode && lodLevel > 1)
            {
                // Apply LOD scaling
                explorationCoords.x = explorationCoords.x / lodLevel;
                explorationCoords.y = explorationCoords.y / lodLevel;

                int visibleWidth = (int)exploredBounds.width / lodLevel;
                int visibleHeight = (int)exploredBounds.height / lodLevel;

                explorationCoords.x = Mathf.Clamp(explorationCoords.x, 0, visibleWidth - 1);
                explorationCoords.y = Mathf.Clamp(explorationCoords.y, 0, visibleHeight - 1);
            }
            else
            {
                explorationCoords.x = Mathf.Clamp(explorationCoords.x, 0, (int)exploredBounds.width - 1);
                explorationCoords.y = Mathf.Clamp(explorationCoords.y, 0, (int)exploredBounds.height - 1);
            }

            Debug.Log($"🔄 PARTIAL: World({worldPosition.x:F1}, {worldPosition.z:F1}) → Base({baseTilePos}) → Exploration({explorationCoords}) [LOD:{lodLevel}]");
            return explorationCoords;
        }
    }

    /// <summary>
    /// Convert exploration coordinates back to world coordinates  
    /// </summary>
    public Vector3 ConvertExplorationToWorldCoordinates(Vector2Int explorationCoords)
    {
        Rect exploredBounds = GetExploredBounds();

        // Check if we're showing the full map
        bool isShowingFullMap = (exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5);

        Vector2Int fullMapCoords;

        if (isShowingFullMap)
        {
            // When showing full map, exploration coordinates ARE the world coordinates (with LOD scaling)
            if (performanceMode && lodLevel > 1)
            {
                // Scale up from LOD coordinates
                fullMapCoords = new Vector2Int(
                    explorationCoords.x * lodLevel,
                    explorationCoords.y * lodLevel
                );
            }
            else
            {
                // Direct mapping
                fullMapCoords = explorationCoords;
            }
        }
        else
        {
            // Normal exploration mode - add bounds offset
            if (performanceMode && lodLevel > 1)
            {
                // Scale up coordinates and add bounds offset
                fullMapCoords = new Vector2Int(
                    (explorationCoords.x * lodLevel) + (int)exploredBounds.x,
                    (explorationCoords.y * lodLevel) + (int)exploredBounds.y
                );
            }
            else
            {
                // Direct conversion with bounds offset
                fullMapCoords = new Vector2Int(
                    explorationCoords.x + (int)exploredBounds.x,
                    explorationCoords.y + (int)exploredBounds.y
                );
            }
        }

        Vector3 worldPos = new Vector3(fullMapCoords.x, 0, fullMapCoords.y);

        Debug.Log($"🔄 Exploration({explorationCoords}) → FullMap({fullMapCoords}) → World({worldPos.x:F1}, {worldPos.z:F1}) [LOD:{lodLevel}, FullMap:{isShowingFullMap}]");

        return worldPos;
    }

    /// <summary>
    /// Synchronize team marker position between coordinate systems
    /// Call this method when switching between journey and exploration systems
    /// </summary>
    public void SynchronizeTeamMarkerPosition()
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return;

        GameObject teamMarker = GameObject.Find("TeamMarker");
        if (teamMarker == null) return;

        // Get current world position from the marker
        Vector3 currentWorldPos = teamMarker.transform.position;

        // Convert to proper exploration coordinates
        Vector2Int correctExplorationCoords = ConvertWorldToExplorationCoordinates(currentWorldPos);

        // Get the current stored position in team placement
        Vector2Int storedPosition = teamPlacement.GetCurrentTeamPosition();

        // Check if there's a mismatch that needs fixing
        if (storedPosition != correctExplorationCoords)
        {
            Debug.Log($"🔧 Coordinate mismatch detected: Stored({storedPosition}) ≠ Calculated({correctExplorationCoords})");
            Debug.Log($"   World position: ({currentWorldPos.x:F1}, {currentWorldPos.z:F1})");

            // Fix the mismatch by updating the stored position to match the world position
            // This preserves the actual visual location of the marker
            teamPlacement.UpdateMarkerAfterMapChange(correctExplorationCoords);

            Debug.Log($"✅ Fixed coordinate mismatch: Updated stored position to ({correctExplorationCoords})");
        }
        else
        {
            Debug.Log($"✅ Coordinates are synchronized: World({currentWorldPos.x:F1}, {currentWorldPos.z:F1}) → Exploration({correctExplorationCoords})");
        }
    }

    /// <summary>
    /// Debug method to show current coordinate state
    /// </summary>
    public void DebugCoordinateState()
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return;

        GameObject teamMarker = GameObject.Find("TeamMarker");
        if (teamMarker == null) return;

        Vector3 worldPos = teamMarker.transform.position;
        Vector2Int storedPos = teamPlacement.GetCurrentTeamPosition();
        Vector2Int calculatedPos = ConvertWorldToExplorationCoordinates(worldPos);
        Rect exploredBounds = GetExploredBounds();
        bool isShowingFullMap = (exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5);

        Debug.Log("=== COORDINATE DEBUG ===");
        Debug.Log($"World Position: ({worldPos.x:F1}, {worldPos.z:F1})");
        Debug.Log($"Stored Position: ({storedPos.x}, {storedPos.y})");
        Debug.Log($"Calculated Position: ({calculatedPos.x}, {calculatedPos.y})");
        Debug.Log($"Explored Bounds: {exploredBounds}");
        Debug.Log($"Showing Full Map: {isShowingFullMap}");
        Debug.Log($"Performance Mode: {performanceMode}, LOD Level: {lodLevel}");
        Debug.Log($"Coordinate Match: {(storedPos == calculatedPos ? "✅ YES" : "❌ NO")}");

        if (storedPos != calculatedPos)
        {
            Debug.Log($"🔧 MISMATCH DETECTED! Use 'FIX: Force Coordinate Sync' to fix this.");
        }

        Debug.Log("========================");
    }

    /// <summary>
    /// Force coordinate synchronization regardless of current state
    /// </summary>
    public void ForceCoordinateSync()
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return;

        GameObject teamMarker = GameObject.Find("TeamMarker");
        if (teamMarker == null) return;

        // Get current world position from the marker
        Vector3 currentWorldPos = teamMarker.transform.position;

        // Convert to proper exploration coordinates
        Vector2Int correctExplorationCoords = ConvertWorldToExplorationCoordinates(currentWorldPos);

        // Force update the stored position
        teamPlacement.UpdateMarkerAfterMapChange(correctExplorationCoords);

        Debug.Log($"🔧 FORCED coordinate sync: World({currentWorldPos.x:F1}, {currentWorldPos.z:F1}) → Exploration({correctExplorationCoords})");
        Debug.Log($"✅ Team marker position forcibly synchronized");
    }

    /// <summary>
    /// Reset team marker to the center of the map (useful when coordinates get messed up)
    /// </summary>
    public void ResetTeamMarkerToMapCenter()
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return;

        // Calculate the center of the full map
        int centerX = fullMapWidth / 2;
        int centerY = fullMapHeight / 2;
        Vector2Int mapCenter = new Vector2Int(centerX, centerY);

        // Check if we're currently showing the full map
        Rect exploredBounds = GetExploredBounds();
        bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5;

        Vector2Int targetPosition;
        if (isShowingFullMap)
        {
            // In full map mode, place at actual center coordinates
            targetPosition = mapCenter;
            Debug.Log($"🎯 Resetting team marker to full map center: ({targetPosition})");
        }
        else
        {
            // In exploration mode, place at center of visible area
            targetPosition = new Vector2Int(
                centerX - (int)exploredBounds.x,
                centerY - (int)exploredBounds.y
            );
            Debug.Log($"🎯 Resetting team marker to exploration center: Full({mapCenter}) → Visible({targetPosition})");
        }

        // Update team marker position
        teamPlacement.UpdateMarkerAfterMapChange(targetPosition);

        Debug.Log($"✅ Team marker reset to map center");
    }    /// <summary>
         /// Generate the complete large map using existing MapMaker2 systems
         /// </summary>
    private void GenerateFullMap()
    {
        Debug.Log($"🌍 Generating full map of size {fullMapWidth}x{fullMapHeight}...");

        // Temporarily modify MapMaker2 settings for large map generation
        int originalWidth = mapMaker.mapWidth;
        int originalHeight = mapMaker.mapHeight;
        int originalSeed = mapMaker.seed;

        mapMaker.mapWidth = fullMapWidth;
        mapMaker.mapHeight = fullMapHeight;

        // Use the same seed for consistency, but initialize it properly
        Random.InitState(originalSeed);
        UnityEngine.Random.InitState(originalSeed);

        // Generate the full map
        fullMapData = new MapData(fullMapWidth, fullMapHeight);
        Debug.Log($"📊 Created MapData with size: {fullMapData.Width}x{fullMapData.Height}");

        // Generate the complete map using MapMaker2's generation system
        mapMaker.GenerateCompleteMap(fullMapData);

        // Ensure roads and features connect properly across the entire map
        PostProcessMapConnectivity();

        // Restore original settings
        mapMaker.mapWidth = originalWidth;
        mapMaker.mapHeight = originalHeight;

        // Debug settlement count in full map
        int townCount = fullMapData.GetTowns().Count;
        int villageCount = fullMapData.GetVillages().Count;
        Debug.Log($"🏘️ Generated full map with {townCount} towns and {villageCount} villages");

        Debug.Log("✅ Full map generation complete");
    }

    /// <summary>
    /// Post-process the map to ensure better connectivity of roads and features
    /// </summary>
    private void PostProcessMapConnectivity()
    {
        Debug.Log("🔧 Post-processing map for better connectivity...");

        // Ensure all settlements are connected by roads
        ConnectSettlementsWithRoads();

        // Smooth terrain transitions to prevent harsh breaks
        SmoothTerrainTransitions();

        // Validate water bodies and rivers for continuity
        ValidateWaterFeatures();

        Debug.Log("✅ Map connectivity post-processing complete");
    }

    /// <summary>
    /// Connect all settlements with roads for better navigation
    /// </summary>
    private void ConnectSettlementsWithRoads()
    {
        var allSettlements = new List<Settlement>();
        allSettlements.AddRange(fullMapData.GetTowns());
        allSettlements.AddRange(fullMapData.GetVillages());

        Debug.Log($"🛣️ Connecting {allSettlements.Count} settlements with roads...");

        for (int i = 0; i < allSettlements.Count - 1; i++)
        {
            for (int j = i + 1; j < allSettlements.Count; j++)
            {
                Settlement from = allSettlements[i];
                Settlement to = allSettlements[j];

                // Only connect nearby settlements (within reasonable distance)
                float distance = Vector2.Distance(from.position, to.position);
                if (distance < 50f) // Adjust distance threshold as needed
                {
                    CreateRoadBetweenPoints(from.position, to.position);
                }
            }
        }
    }

    /// <summary>
    /// Create a road between two points
    /// </summary>
    private void CreateRoadBetweenPoints(Vector2Int start, Vector2Int end)
    {
        // Simple pathfinding - create L-shaped or direct path
        List<Vector2Int> roadPath = new List<Vector2Int>();

        // Direct line approach (can be enhanced with A* pathfinding later)
        Vector2Int current = start;
        Vector2Int diff = end - start;

        // Horizontal movement first
        int stepX = diff.x > 0 ? 1 : -1;
        while (current.x != end.x)
        {
            roadPath.Add(current);
            current.x += stepX;
        }

        // Vertical movement
        int stepY = diff.y > 0 ? 1 : -1;
        while (current.y != end.y)
        {
            roadPath.Add(current);
            current.y += stepY;
        }
        roadPath.Add(end);

        // Place road tiles
        foreach (var point in roadPath)
        {
            if (IsValidExplorationPosition(point.x, point.y))
            {
                MapTile tile = fullMapData.GetTile(point.x, point.y);
                if (tile != null && !tile.IsWater())
                {
                    // Set road feature (assuming FeatureType.Road exists)
                    tile.featureType = FeatureType.Road;
                }
            }
        }
    }

    /// <summary>
    /// Smooth terrain transitions to prevent harsh breaks
    /// </summary>
    private void SmoothTerrainTransitions()
    {
        Debug.Log("🌄 Smoothing terrain transitions...");

        // Apply smoothing filter to height values
        for (int x = 1; x < fullMapWidth - 1; x++)
        {
            for (int y = 1; y < fullMapHeight - 1; y++)
            {
                MapTile center = fullMapData.GetTile(x, y);
                if (center == null) continue;

                // Get surrounding tiles
                List<MapTile> neighbors = new List<MapTile>();
                for (int dx = -1; dx <= 1; dx++)
                {
                    for (int dy = -1; dy <= 1; dy++)
                    {
                        if (dx == 0 && dy == 0) continue;
                        MapTile neighbor = fullMapData.GetTile(x + dx, y + dy);
                        if (neighbor != null) neighbors.Add(neighbor);
                    }
                }

                if (neighbors.Count > 0)
                {
                    // Average the height with neighbors for smoother transitions
                    float avgHeight = neighbors.Average(t => t.height);
                    center.height = (center.height + avgHeight) * 0.5f;
                }
            }
        }
    }

    /// <summary>
    /// Validate and fix water features for better continuity
    /// </summary>
    private void ValidateWaterFeatures()
    {
        Debug.Log("🌊 Validating water features...");

        // Ensure water tiles form connected bodies
        // This is a simplified version - can be enhanced for better water flow
        for (int x = 0; x < fullMapWidth; x++)
        {
            for (int y = 0; y < fullMapHeight; y++)
            {
                MapTile tile = fullMapData.GetTile(x, y);
                if (tile != null && tile.IsWater())
                {
                    // Ensure isolated water tiles have proper connections
                    EnsureWaterConnection(x, y);
                }
            }
        }
    }

    /// <summary>
    /// Ensure water tile has proper connections to other water
    /// </summary>
    private void EnsureWaterConnection(int x, int y)
    {
        // Count water neighbors
        int waterNeighbors = 0;
        for (int dx = -1; dx <= 1; dx++)
        {
            for (int dy = -1; dy <= 1; dy++)
            {
                if (dx == 0 && dy == 0) continue;
                if (IsValidExplorationPosition(x + dx, y + dy))
                {
                    MapTile neighbor = fullMapData.GetTile(x + dx, y + dy);
                    if (neighbor != null && neighbor.IsWater())
                    {
                        waterNeighbors++;
                    }
                }
            }
        }

        // If isolated water tile, convert to land or extend water
        if (waterNeighbors == 0)
        {
            MapTile tile = fullMapData.GetTile(x, y);
            if (tile != null)
            {
                // Convert single water tiles to plains to prevent isolated lakes
                tile.terrainType = TerrainType.Plains;
            }
        }
    }

    /// <summary>
    /// Reveal the initial area around the map center
    /// </summary>
    private void RevealInitialArea()
    {
        int centerX = fullMapWidth / 2;
        int centerY = fullMapHeight / 2;

        int halfSize = initialVisibleSize / 2;

        for (int x = centerX - halfSize; x < centerX + halfSize; x++)
        {
            for (int y = centerY - halfSize; y < centerY + halfSize; y++)
            {
                if (IsValidExplorationPosition(x, y))
                {
                    exploredMask[x, y] = true;
                }
            }
        }

        // Ensure we have at least one settlement in the initial area
        EnsureSettlementsInInitialArea(centerX, centerY, halfSize);

        Debug.Log($"🔍 Initial area revealed: {initialVisibleSize}x{initialVisibleSize} around center ({centerX}, {centerY})");
    }

    /// <summary>
    /// Get the correct initial team position in visible map coordinates
    /// </summary>
    public Vector2Int GetInitialTeamPosition()
    {
        // The team should be placed at the center of the visible map
        // Since we start with the full map center revealed, and the visible map shows just the explored area
        Rect exploredBounds = GetExploredBounds();

        int centerX = fullMapWidth / 2;
        int centerY = fullMapHeight / 2;

        // Convert full map center to visible map coordinates
        Vector2Int visiblePosition = new Vector2Int(
            centerX - (int)exploredBounds.x,
            centerY - (int)exploredBounds.y
        );

        Debug.Log($"🎯 Initial team position: Full({centerX}, {centerY}) → Visible({visiblePosition.x}, {visiblePosition.y})");

        return visiblePosition;
    }

    /// <summary>
    /// Ensure there are settlements in the initial revealed area
    /// </summary>
    private void EnsureSettlementsInInitialArea(int centerX, int centerY, int halfSize)
    {
        // Check if there are already settlements in the initial area
        bool hasSettlements = false;
        var allSettlements = new List<Settlement>();
        allSettlements.AddRange(fullMapData.GetTowns());
        allSettlements.AddRange(fullMapData.GetVillages());

        foreach (var settlement in allSettlements)
        {
            if (settlement.position.x >= centerX - halfSize && settlement.position.x < centerX + halfSize &&
                settlement.position.y >= centerY - halfSize && settlement.position.y < centerY + halfSize)
            {
                hasSettlements = true;
                break;
            }
        }

        // If no settlements in initial area, place one near the center
        if (!hasSettlements)
        {
            Debug.Log("⚠️ No settlements in initial area, creating one...");

            // Find a good spot for a settlement near the center
            Vector2Int settlementPos = FindSuitableSettlementPosition(centerX, centerY, halfSize - 5);

            if (settlementPos != Vector2Int.zero)
            {
                Settlement newSettlement = new Settlement("Starting Village", SettlementType.Village, settlementPos);
                fullMapData.AddSettlement(newSettlement);

                Debug.Log($"🏘️ Created starting settlement at ({settlementPos.x}, {settlementPos.y})");
            }
        }
    }

    /// <summary>
    /// Find a suitable position for a settlement within the given area
    /// </summary>
    private Vector2Int FindSuitableSettlementPosition(int centerX, int centerY, int searchRadius)
    {
        for (int radius = 5; radius <= searchRadius; radius += 5)
        {
            for (int angle = 0; angle < 360; angle += 45)
            {
                float radians = angle * Mathf.Deg2Rad;
                int x = centerX + (int)(radius * Mathf.Cos(radians));
                int y = centerY + (int)(radius * Mathf.Sin(radians));

                if (IsValidExplorationPosition(x, y))
                {
                    MapTile tile = fullMapData.GetTile(x, y);
                    if (tile != null && !tile.IsWater())
                    {
                        return new Vector2Int(x, y);
                    }
                }
            }
        }

        // If no suitable position found, use center as fallback
        return new Vector2Int(centerX, centerY);
    }

    /// <summary>
    /// Check if exploration should be triggered based on player position
    /// </summary>
    public bool ShouldExplore(Vector2 playerPosition, MapData currentMapData)
    {
        // Check cooldown first
        if (Time.time - lastExplorationTime < explorationCooldown)
        {
            return false;
        }

        // Convert player position to full map coordinates
        Vector2Int playerFullMapPos = GetPlayerPositionInFullMap(playerPosition, currentMapData);

        // Check distance to unexplored edges
        bool shouldExplore = IsNearUnexploredEdge(playerFullMapPos);

        if (shouldExplore)
        {
            Debug.Log($"✅ Exploration triggered! Player at {playerFullMapPos} near unexplored edge");
        }

        return shouldExplore;
    }

    /// <summary>
    /// Reveal new areas around the player position
    /// </summary>
    public void ExploreNewAreas(Vector2 playerPosition, MapData currentMapData)
    {
        // Set exploration cooldown
        lastExplorationTime = Time.time;

        Vector2Int playerFullMapPos = GetPlayerPositionInFullMap(playerPosition, currentMapData);

        Debug.Log($"🔍 Exploring new areas around player position {playerFullMapPos}");

        // Determine which direction to explore
        ExplorationDirection direction = GetExplorationDirection(playerFullMapPos);

        // Reveal new chunk in that direction
        RevealChunk(playerFullMapPos, direction);

        // Update the visible map
        UpdateVisibleMap();
    }

    /// <summary>
    /// Convert player position from current map to full map coordinates
    /// </summary>
    private Vector2Int GetPlayerPositionInFullMap(Vector2 playerPosition, MapData currentMapData)
    {
        // Find the offset of the current visible area within the full map
        Vector2Int visibleOffset = GetCurrentVisibleOffset(currentMapData);

        // Ensure player position is valid within current map bounds
        int clampedX = Mathf.Clamp((int)playerPosition.x, 0, currentMapData.Width - 1);
        int clampedY = Mathf.Clamp((int)playerPosition.y, 0, currentMapData.Height - 1);

        Vector2Int fullMapPos = new Vector2Int(
            visibleOffset.x + clampedX,
            visibleOffset.y + clampedY
        );

        return fullMapPos;
    }

    /// <summary>
    /// Get the offset of the current visible area within the full map
    /// </summary>
    private Vector2Int GetCurrentVisibleOffset(MapData currentMapData)
    {
        // Find the bounds of the explored area
        Rect exploredBounds = GetExploredBounds();
        Vector2Int offset = new Vector2Int((int)exploredBounds.x, (int)exploredBounds.y);

        return offset;
    }

    /// <summary>
    /// Check if player is near an unexplored edge
    /// </summary>
    private bool IsNearUnexploredEdge(Vector2Int playerPos)
    {
        // Validate player position is within full map bounds
        if (!IsValidExplorationPosition(playerPos.x, playerPos.y))
        {
            Debug.LogWarning($"⚠️ Player position {playerPos} is outside full map bounds!");
            return false;
        }

        // First check: Is player near the edge of the currently explored area?
        Rect exploredBounds = GetExploredBounds();

        // Calculate distances to each edge of explored area
        float distToLeft = playerPos.x - exploredBounds.x;
        float distToRight = (exploredBounds.x + exploredBounds.width - 1) - playerPos.x;
        float distToBottom = playerPos.y - exploredBounds.y;
        float distToTop = (exploredBounds.y + exploredBounds.height - 1) - playerPos.y;

        float minDistToExploredEdge = Mathf.Min(distToLeft, distToRight, distToBottom, distToTop);

        if (minDistToExploredEdge <= explorationDistance)
        {
            Debug.Log($"🎯 Player at {playerPos} is {minDistToExploredEdge} tiles from explored edge - triggering exploration!");
            return true;
        }

        // Second check: Look for unexplored areas within exploration distance
        for (int dx = -(int)explorationDistance; dx <= explorationDistance; dx++)
        {
            for (int dy = -(int)explorationDistance; dy <= explorationDistance; dy++)
            {
                int checkX = playerPos.x + dx;
                int checkY = playerPos.y + dy;

                if (IsValidExplorationPosition(checkX, checkY) && !exploredMask[checkX, checkY])
                {
                    Debug.Log($"🎯 Found unexplored area at ({checkX}, {checkY}) near player {playerPos}");
                    return true;
                }
            }
        }

        return false;
    }

    /// <summary>
    /// Determine which direction to explore based on player position
    /// </summary>
    private ExplorationDirection GetExplorationDirection(Vector2Int playerPos)
    {
        // Find the closest unexplored edge
        float minDistance = float.MaxValue;
        ExplorationDirection closestDirection = ExplorationDirection.North;

        // Check each direction
        float northDist = CheckDirectionDistance(playerPos, ExplorationDirection.North);
        float southDist = CheckDirectionDistance(playerPos, ExplorationDirection.South);
        float eastDist = CheckDirectionDistance(playerPos, ExplorationDirection.East);
        float westDist = CheckDirectionDistance(playerPos, ExplorationDirection.West);

        // Find the minimum distance
        if (northDist <= minDistance) { minDistance = northDist; closestDirection = ExplorationDirection.North; }
        if (southDist <= minDistance) { minDistance = southDist; closestDirection = ExplorationDirection.South; }
        if (eastDist <= minDistance) { minDistance = eastDist; closestDirection = ExplorationDirection.East; }
        if (westDist <= minDistance) { minDistance = westDist; closestDirection = ExplorationDirection.West; }

        Debug.Log($"🧭 Exploration direction: {closestDirection} (N:{northDist:F0}, S:{southDist:F0}, E:{eastDist:F0}, W:{westDist:F0})");

        return closestDirection;
    }

    private float CheckDirectionDistance(Vector2Int playerPos, ExplorationDirection direction)
    {
        Vector2Int checkPos = playerPos;
        float distance = 0;

        // Move in the specified direction until we hit unexplored area
        Vector2Int dirVector = GetDirectionVector(direction);

        while (IsValidExplorationPosition(checkPos.x, checkPos.y) && exploredMask[checkPos.x, checkPos.y])
        {
            checkPos += dirVector;
            distance++;

            // Safety check to prevent infinite loops
            if (distance > 100)
            {
                Debug.LogWarning($"⚠️ Direction check exceeded 100 steps for {direction}, breaking");
                break;
            }
        }

        return distance;
    }

    private Vector2Int GetDirectionVector(ExplorationDirection direction)
    {
        switch (direction)
        {
            case ExplorationDirection.North: return new Vector2Int(0, 1);
            case ExplorationDirection.South: return new Vector2Int(0, -1);
            case ExplorationDirection.East: return new Vector2Int(1, 0);
            case ExplorationDirection.West: return new Vector2Int(-1, 0);
            default: return Vector2Int.zero;
        }
    }

    /// <summary>
    /// Reveal a chunk of the map in the specified direction
    /// </summary>
    private void RevealChunk(Vector2Int playerPos, ExplorationDirection direction)
    {
        Vector2Int chunkCenter = GetChunkCenterForDirection(playerPos, direction);

        int halfChunk = explorationChunkSize / 2;

        for (int x = chunkCenter.x - halfChunk; x < chunkCenter.x + halfChunk; x++)
        {
            for (int y = chunkCenter.y - halfChunk; y < chunkCenter.y + halfChunk; y++)
            {
                if (IsValidExplorationPosition(x, y))
                {
                    exploredMask[x, y] = true;
                }
            }
        }

        Debug.Log($"✅ Revealed {explorationChunkSize}x{explorationChunkSize} chunk at {chunkCenter} in direction {direction}");
    }

    private Vector2Int GetChunkCenterForDirection(Vector2Int playerPos, ExplorationDirection direction)
    {
        switch (direction)
        {
            case ExplorationDirection.North:
                return new Vector2Int(playerPos.x, playerPos.y + explorationChunkSize);
            case ExplorationDirection.South:
                return new Vector2Int(playerPos.x, playerPos.y - explorationChunkSize);
            case ExplorationDirection.East:
                return new Vector2Int(playerPos.x + explorationChunkSize, playerPos.y);
            case ExplorationDirection.West:
                return new Vector2Int(playerPos.x - explorationChunkSize, playerPos.y);
            default:
                return playerPos;
        }
    }

    /// <summary>
    /// Update the visible map data based on explored areas
    /// </summary>
    private void UpdateVisibleMap()
    {
        if (performanceMode)
        {
            UpdateVisibleMapOptimized();
        }
        else
        {
            UpdateVisibleMapStandard();
        }
    }

    /// <summary>
    /// Standard map update for smaller maps
    /// </summary>
    private void UpdateVisibleMapStandard()
    {
        // Find the bounds of the explored area
        Rect exploredBounds = GetExploredBounds();

        // Create new map data for the visible area
        int visibleWidth = (int)exploredBounds.width;
        int visibleHeight = (int)exploredBounds.height;

        MapData newVisibleMap = new MapData(visibleWidth, visibleHeight);

        // Copy explored tiles to the visible map
        for (int x = 0; x < visibleWidth; x++)
        {
            for (int y = 0; y < visibleHeight; y++)
            {
                int fullMapX = (int)exploredBounds.x + x;
                int fullMapY = (int)exploredBounds.y + y;

                if (IsValidExplorationPosition(fullMapX, fullMapY) && exploredMask[fullMapX, fullMapY])
                {
                    MapTile sourceTile = fullMapData.GetTile(fullMapX, fullMapY);
                    MapTile destTile = newVisibleMap.GetTile(x, y);

                    if (sourceTile != null && destTile != null)
                    {
                        CopyTileData(sourceTile, destTile);
                    }
                }
            }
        }

        // Copy settlements from the full map to the visible map (adjusted coordinates)
        CopySettlementsToVisibleMap(newVisibleMap, exploredBounds);

        // Update the map maker's current map data
        mapMaker.SetMapData(newVisibleMap);

        // Fix team marker position after map bounds change
        FixTeamMarkerPosition(exploredBounds);

        Debug.Log($"🗺️ Updated visible map: {visibleWidth}x{visibleHeight}");

        // Debug settlement count
        int townCount = newVisibleMap.GetTowns().Count;
        int villageCount = newVisibleMap.GetVillages().Count;
        Debug.Log($"🏘️ Visible settlements: {townCount} towns, {villageCount} villages");
    }

    /// <summary>
    /// Optimized map update for large maps using Level of Detail
    /// </summary>
    private void UpdateVisibleMapOptimized()
    {
        Debug.Log($"⚡ Using optimized map update with LOD level {lodLevel}...");

        // Find the bounds of the explored area
        Rect exploredBounds = GetExploredBounds();

        // Calculate downsampled dimensions
        int visibleWidth = (int)exploredBounds.width / lodLevel;
        int visibleHeight = (int)exploredBounds.height / lodLevel;

        // Ensure minimum size
        visibleWidth = Mathf.Max(visibleWidth, 50);
        visibleHeight = Mathf.Max(visibleHeight, 50);

        MapData newVisibleMap = new MapData(visibleWidth, visibleHeight);

        // Copy tiles with Level of Detail sampling
        for (int x = 0; x < visibleWidth; x++)
        {
            for (int y = 0; y < visibleHeight; y++)
            {
                // Sample from the full map using LOD
                int fullMapX = (int)exploredBounds.x + (x * lodLevel);
                int fullMapY = (int)exploredBounds.y + (y * lodLevel);

                if (IsValidExplorationPosition(fullMapX, fullMapY) && exploredMask[fullMapX, fullMapY])
                {
                    // Average surrounding tiles for better representation
                    MapTile sampledTile = SampleTileWithLOD(fullMapX, fullMapY, lodLevel);
                    MapTile destTile = newVisibleMap.GetTile(x, y);

                    if (sampledTile != null && destTile != null)
                    {
                        CopyTileData(sampledTile, destTile);
                    }
                }
            }
        }

        // Copy settlements with adjusted coordinates for LOD
        CopySettlementsToVisibleMapLOD(newVisibleMap, exploredBounds, lodLevel);

        // Update the map maker's current map data
        mapMaker.SetMapData(newVisibleMap);

        // Fix team marker position with LOD adjustment
        FixTeamMarkerPositionLOD(exploredBounds, lodLevel);

        Debug.Log($"⚡ Optimized visible map updated: {visibleWidth}x{visibleHeight} (LOD {lodLevel})");
    }

    /// <summary>
    /// Sample a tile from the full map using Level of Detail
    /// </summary>
    private MapTile SampleTileWithLOD(int centerX, int centerY, int sampleSize)
    {
        List<MapTile> sampleTiles = new List<MapTile>();

        // Collect tiles in the sample area
        for (int dx = 0; dx < sampleSize && dx + centerX < fullMapWidth; dx++)
        {
            for (int dy = 0; dy < sampleSize && dy + centerY < fullMapHeight; dy++)
            {
                MapTile tile = fullMapData.GetTile(centerX + dx, centerY + dy);
                if (tile != null && exploredMask[centerX + dx, centerY + dy])
                {
                    sampleTiles.Add(tile);
                }
            }
        }

        if (sampleTiles.Count == 0)
            return fullMapData.GetTile(centerX, centerY);

        // Return the most common terrain type in the sample
        var terrainGroups = sampleTiles.GroupBy(t => t.terrainType);
        var mostCommonTerrain = terrainGroups.OrderByDescending(g => g.Count()).First().Key;

        // Create a representative tile
        MapTile representativeTile = fullMapData.GetTile(centerX, centerY);
        if (representativeTile != null)
        {
            representativeTile.terrainType = mostCommonTerrain;
            representativeTile.height = sampleTiles.Average(t => t.height);
        }

        return representativeTile;
    }

    /// <summary>
    /// Copy settlements to visible map with LOD adjustment
    /// </summary>
    private void CopySettlementsToVisibleMapLOD(MapData visibleMap, Rect exploredBounds, int lod)
    {
        var fullTowns = fullMapData.GetTowns();
        var fullVillages = fullMapData.GetVillages();

        foreach (var town in fullTowns)
        {
            if (town.position.x >= exploredBounds.x && town.position.x < exploredBounds.x + exploredBounds.width &&
                town.position.y >= exploredBounds.y && town.position.y < exploredBounds.y + exploredBounds.height)
            {
                Vector2Int adjustedPos = new Vector2Int(
                    (town.position.x - (int)exploredBounds.x) / lod,
                    (town.position.y - (int)exploredBounds.y) / lod
                );

                Settlement adjustedTown = new Settlement(town.name, town.Type, adjustedPos);
                visibleMap.AddSettlement(adjustedTown);
            }
        }

        foreach (var village in fullVillages)
        {
            if (village.position.x >= exploredBounds.x && village.position.x < exploredBounds.x + exploredBounds.width &&
                village.position.y >= exploredBounds.y && village.position.y < exploredBounds.y + exploredBounds.height)
            {
                Vector2Int adjustedPos = new Vector2Int(
                    (village.position.x - (int)exploredBounds.x) / lod,
                    (village.position.y - (int)exploredBounds.y) / lod
                );

                Settlement adjustedVillage = new Settlement(village.name, village.Type, adjustedPos);
                visibleMap.AddSettlement(adjustedVillage);
            }
        }
    }

    /// <summary>
    /// Fix team marker position with LOD adjustment
    /// </summary>
    private void FixTeamMarkerPositionLOD(Rect exploredBounds, int lod)
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return;

        GameObject teamMarker = GameObject.Find("TeamMarker");
        if (teamMarker == null) return;

        Vector3 currentWorldPos = teamMarker.transform.position;

        // Convert to LOD-adjusted coordinates
        Vector2Int newTilePos = new Vector2Int(
            Mathf.RoundToInt(currentWorldPos.x) / lod,
            Mathf.RoundToInt(currentWorldPos.z) / lod
        );

        int visibleWidth = (int)exploredBounds.width / lod;
        int visibleHeight = (int)exploredBounds.height / lod;

        newTilePos.x = Mathf.Clamp(newTilePos.x, 0, visibleWidth - 1);
        newTilePos.y = Mathf.Clamp(newTilePos.y, 0, visibleHeight - 1);

        teamPlacement.UpdateMarkerAfterMapChange(newTilePos);

        Debug.Log($"⚡ Fixed team marker with LOD {lod}: World({currentWorldPos.x:F1}, {currentWorldPos.y:F1}) → Tile({newTilePos.x}, {newTilePos.y})");
    }

    /// <summary>
    /// Fix team marker position after map bounds change
    /// </summary>
    private void FixTeamMarkerPosition(Rect exploredBounds)
    {
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return;

        // Get the team marker GameObject to preserve world position
        GameObject teamMarker = GameObject.Find("TeamMarker");
        if (teamMarker == null) return;

        // Get current world position
        Vector3 currentWorldPos = teamMarker.transform.position;

        // Convert world position to new tile coordinates
        // Assuming 1 unit = 1 tile (adjust if your tile scale is different)
        Vector2Int newTilePos = new Vector2Int(
            Mathf.RoundToInt(currentWorldPos.x),
            Mathf.RoundToInt(currentWorldPos.z)
        );

        // Ensure the position is within the new visible map bounds
        int visibleWidth = (int)exploredBounds.width;
        int visibleHeight = (int)exploredBounds.height;

        newTilePos.x = Mathf.Clamp(newTilePos.x, 0, visibleWidth - 1);
        newTilePos.y = Mathf.Clamp(newTilePos.y, 0, visibleHeight - 1);

        // Update the team placement with the corrected position
        teamPlacement.UpdateMarkerAfterMapChange(newTilePos);

        Debug.Log($"🔧 Fixed team marker: World({currentWorldPos.x:F1}, {currentWorldPos.z:F1}) → Tile({newTilePos.x}, {newTilePos.y})");
    }    /// <summary>
         /// Copy settlements from full map to visible map, adjusting coordinates
         /// </summary>
    private void CopySettlementsToVisibleMap(MapData visibleMap, Rect exploredBounds)
    {
        // Get settlements from full map
        var fullTowns = fullMapData.GetTowns();
        var fullVillages = fullMapData.GetVillages();

        foreach (var town in fullTowns)
        {
            // Check if settlement is within explored bounds
            if (town.position.x >= exploredBounds.x && town.position.x < exploredBounds.x + exploredBounds.width &&
                town.position.y >= exploredBounds.y && town.position.y < exploredBounds.y + exploredBounds.height)
            {
                // Adjust coordinates to visible map
                Vector2Int adjustedPos = new Vector2Int(
                    town.position.x - (int)exploredBounds.x,
                    town.position.y - (int)exploredBounds.y
                );

                // Create new settlement with adjusted position
                Settlement adjustedTown = new Settlement(town.name, town.Type, adjustedPos);
                visibleMap.AddSettlement(adjustedTown);
            }
        }

        foreach (var village in fullVillages)
        {
            // Check if settlement is within explored bounds
            if (village.position.x >= exploredBounds.x && village.position.x < exploredBounds.x + exploredBounds.width &&
                village.position.y >= exploredBounds.y && village.position.y < exploredBounds.y + exploredBounds.height)
            {
                // Adjust coordinates to visible map
                Vector2Int adjustedPos = new Vector2Int(
                    village.position.x - (int)exploredBounds.x,
                    village.position.y - (int)exploredBounds.y
                );

                // Create new settlement with adjusted position
                Settlement adjustedVillage = new Settlement(village.name, village.Type, adjustedPos);
                visibleMap.AddSettlement(adjustedVillage);
            }
        }
    }

    private Rect GetExploredBounds()
    {
        int minX = fullMapWidth, maxX = 0;
        int minY = fullMapHeight, maxY = 0;

        for (int x = 0; x < fullMapWidth; x++)
        {
            for (int y = 0; y < fullMapHeight; y++)
            {
                if (exploredMask[x, y])
                {
                    minX = Mathf.Min(minX, x);
                    maxX = Mathf.Max(maxX, x);
                    minY = Mathf.Min(minY, y);
                    maxY = Mathf.Max(maxY, y);
                }
            }
        }

        return new Rect(minX, minY, maxX - minX + 1, maxY - minY + 1);
    }

    /// <summary>
    /// Public method to get explored bounds for camera positioning
    /// </summary>
    public Rect GetExploredBoundsForCamera()
    {
        return GetExploredBounds();
    }

    /// <summary>
    /// Update team marker position to account for new visible map coordinates
    /// </summary>
    private void UpdateTeamMarkerPosition(Rect exploredBounds)
    {
        // Get the SimpleTeamPlacement instance
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null)
        {
            Debug.LogWarning("⚠️ SimpleTeamPlacement not found - cannot update team marker position");
            return;
        }

        // Get current team position in full map coordinates
        Vector2Int currentFullMapPos = GetCurrentTeamPositionInFullMap();
        if (currentFullMapPos == Vector2Int.zero)
        {
            Debug.LogWarning("⚠️ Could not determine current team position in full map");
            return;
        }

        // Convert full map position to new visible map coordinates
        Vector2Int newVisiblePos = new Vector2Int(
            currentFullMapPos.x - (int)exploredBounds.x,
            currentFullMapPos.y - (int)exploredBounds.y
        );

        // Validate the new position is within visible bounds
        if (newVisiblePos.x >= 0 && newVisiblePos.x < exploredBounds.width &&
            newVisiblePos.y >= 0 && newVisiblePos.y < exploredBounds.height)
        {
            // Update the team marker position
            teamPlacement.UpdateMarkerAfterMapChange(newVisiblePos);

            Debug.Log($"🎯 Updated team marker from full map pos {currentFullMapPos} to visible pos {newVisiblePos}");
        }
        else
        {
            Debug.LogWarning($"⚠️ Calculated team position {newVisiblePos} is outside visible bounds {exploredBounds}");
        }
    }

    /// <summary>
    /// Get current team position in full map coordinates
    /// </summary>
    private Vector2Int GetCurrentTeamPositionInFullMap()
    {
        // Try to get team position from SimpleTeamPlacement
        SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType<SimpleTeamPlacement>();
        if (teamPlacement == null) return Vector2Int.zero;

        // Get current visible map position
        Vector2Int currentVisiblePos = teamPlacement.GetCurrentTeamPosition();
        if (currentVisiblePos == Vector2Int.zero) return Vector2Int.zero;

        // Convert to full map coordinates
        Vector2Int visibleOffset = GetCurrentVisibleOffset(mapMaker.GetMapData());
        Vector2Int fullMapPos = new Vector2Int(
            visibleOffset.x + currentVisiblePos.x,
            visibleOffset.y + currentVisiblePos.y
        );

        return fullMapPos;
    }

    /// <summary>
    /// Copy tile data from source to destination
    /// </summary>
    private void CopyTileData(MapTile source, MapTile destination)
    {
        destination.terrainType = source.terrainType;
        destination.height = source.height;
        destination.isWalkable = source.isWalkable;
        destination.featureType = source.featureType;
        destination.name = source.name;
        // Copy any other tile properties as needed
    }

    private bool IsValidExplorationPosition(int x, int y)
    {
        return x >= 0 && x < fullMapWidth && y >= 0 && y < fullMapHeight;
    }

    /// <summary>
    /// Get exploration progress information
    /// </summary>
    public ExplorationInfo GetExplorationInfo()
    {
        int exploredTiles = 0;
        for (int x = 0; x < fullMapWidth; x++)
        {
            for (int y = 0; y < fullMapHeight; y++)
            {
                if (exploredMask[x, y])
                    exploredTiles++;
            }
        }

        int totalTiles = fullMapWidth * fullMapHeight;
        float explorationPercentage = (float)exploredTiles / totalTiles * 100f;

        return new ExplorationInfo
        {
            exploredTiles = exploredTiles,
            totalTiles = totalTiles,
            explorationPercentage = explorationPercentage,
            fullMapSize = new Vector2Int(fullMapWidth, fullMapHeight)
        };
    }

    /// <summary>
    /// DEBUG: Get detailed exploration info for debugging
    /// </summary>
    public void DebugExplorationState(Vector2 playerPos, MapData currentMapData)
    {
        Vector2Int playerFullMapPos = GetPlayerPositionInFullMap(playerPos, currentMapData);
        Rect exploredBounds = GetExploredBounds();

        Debug.Log("=== EXPLORATION DEBUG ===");
        Debug.Log($"Player Visible Pos: {playerPos}");
        Debug.Log($"Player Full Map Pos: {playerFullMapPos}");
        Debug.Log($"Explored Bounds: {exploredBounds}");
        Debug.Log($"Current Map Size: {currentMapData.Width}x{currentMapData.Height}");
        Debug.Log($"Full Map Size: {fullMapWidth}x{fullMapHeight}");

        // Check distances to edges
        float distToLeft = playerFullMapPos.x - exploredBounds.x;
        float distToRight = (exploredBounds.x + exploredBounds.width - 1) - playerFullMapPos.x;
        float distToBottom = playerFullMapPos.y - exploredBounds.y;
        float distToTop = (exploredBounds.y + exploredBounds.height - 1) - playerFullMapPos.y;

        Debug.Log($"Distance to edges - Left: {distToLeft}, Right: {distToRight}, Bottom: {distToBottom}, Top: {distToTop}");
        Debug.Log($"Exploration Distance Threshold: {explorationDistance}");
        Debug.Log($"Should Explore: {IsNearUnexploredEdge(playerFullMapPos)}");
        Debug.Log($"Last Exploration Time: {lastExplorationTime}, Current Time: {Time.time}, Cooldown: {explorationCooldown}");
        Debug.Log("========================");
    }

    public enum ExplorationDirection
    {
        North, South, East, West
    }
}

/// <summary>
/// Information about exploration progress
/// </summary>
public struct ExplorationInfo
{
    public int exploredTiles;
    public int totalTiles;
    public float explorationPercentage;
    public Vector2Int fullMapSize;
}
