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

/// <summary>
/// New comprehensive travel system that handles movement costs, pathfinding, and visual planning.
/// Integrates with SimpleTeamPlacement and MapMaker2 for seamless map-based travel.
/// </summary>
public class TeamTravelSystem : MonoBehaviour
{
    [Header("Movement Costs")]
    [Range(0.1f, 5f)]
    public float plainsMovementCost = 1f;
    [Range(0.1f, 5f)]
    public float forestMovementCost = 2f;
    [Range(0.1f, 5f)]
    public float mountainMovementCost = 4f;
    [Range(0.1f, 2f)]
    public float roadMovementCost = 0.5f;
    [Range(0.1f, 2f)]
    public float townMovementCost = 0.1f; // Almost instant travel inside towns
    [Range(0.1f, 2f)]
    public float bridgeMovementCost = 0.6f;

    [Header("Special Travel Costs")]
    [Range(1, 100)]
    public int ferryBaseCost = 25; // Gold cost for ferry
    [Range(0.1f, 2f)]
    public float ferryMovementCost = 0.7f; // Faster than walking but costs money
    [Range(1, 50)]
    public int tunnelTorchCost = 10; // Torch cost for tunnel travel
    [Range(0.1f, 2f)]
    public float tunnelWithTorchCost = 0.8f; // Fast with torch
    [Range(1f, 5f)]
    public float tunnelWithoutTorchCost = 3f; // Slow and dangerous without torch
    [Range(1, 20)]
    public int bridgeTollCost = 5; // Gold cost for major bridge crossings
    [Range(1, 30)]
    public int mountainPassCost = 15; // Guide cost for dangerous mountain passes

    [Header("River Crossing")]
    [Range(2f, 10f)]
    public float riverCrossingCost = 2f; // Reduced from 6f - more reasonable river crossing
    [Range(1f, 8f)]
    public float lakeCrossingCost = 2.5f; // Reduced from 4f - more reasonable lake crossing
    [Range(5f, 15f)]
    public float oceanCrossingCost = 8f; // Reduced from 10f but still expensive

    [Header("Visual Path Settings")]
    public Material pathLineMaterial;
    public Color standardPathColor = Color.blue;
    public Color expensivePathColor = Color.red;
    public Color alternativePathColor = Color.yellow;
    [Range(0.1f, 5f)]
    public float pathLineWidth = 2.5f; // Increased for much better visibility
    [Range(-10f, 10f)]
    public float pathLineHeight = 1f; // Height above map tiles for path lines

    [Header("Debug")]
    public bool showDebugLogs = false;
    public bool showMovementCosts = false;

    // References
    private SimpleTeamPlacement teamPlacement;
    private MapMaker2 mapMaker;
    private Camera mapCamera;
    private TravelUI travelUI;

    // Travel state
    private Vector2Int? plannedDestination;
    private List<TravelRoute> availableRoutes = new List<TravelRoute>();
    private List<GameObject> currentPathVisualizations = new List<GameObject>(); // Store multiple route lines
    private bool isTraveling = false;
    private int currentRouteIndex = 0; // For cycling through route visualizations

    // Journey cancellation
    private bool shouldCancelJourney = false;
    private Coroutine currentTravelCoroutine = null;
    private TravelRoute currentRoute = null;

    // Time skip functionality
    [Header("Time Controls")]
    public float timeMultiplier = 1f; // Current time speed multiplier
    public float[] timeSpeedOptions = { 1f, 2f, 4f, 8f }; // Available speed options
    private int currentTimeSpeedIndex = 0;

    // Static instance
    public static TeamTravelSystem Instance { get; private set; }

    void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Debug.LogWarning("Multiple TeamTravelSystem instances found. Destroying this one.");
            Destroy(gameObject);
            return;
        }
    }

    void Start()
    {
        // Find required components
        teamPlacement = FindFirstObjectByType<SimpleTeamPlacement>();
        mapMaker = FindFirstObjectByType<MapMaker2>();
        mapCamera = Camera.main;
        travelUI = FindFirstObjectByType<TravelUI>();

        // Initialize pathLineMaterial if not assigned
        if (pathLineMaterial == null)
        {
            pathLineMaterial = CreateDefaultPathMaterial();
        }

        if (teamPlacement == null)
        {
            Debug.LogError("SimpleTeamPlacement not found! TeamTravelSystem requires it.");
        }

        if (mapMaker == null)
        {
            Debug.LogError("MapMaker2 not found! TeamTravelSystem requires it.");
        }

        if (travelUI == null)
        {
            Debug.LogWarning("TravelUI not found! UI features will be limited.");
        }
    }

    void Update()
    {
        HandleInput();
    }

    private void HandleInput()
    {
        // Time speed controls (available during travel)
        if (isTraveling)
        {
            if (Input.GetKeyDown(KeyCode.Period) || Input.GetKeyDown(KeyCode.RightArrow)) // > key or right arrow
            {
                IncreaseTimeSpeed();
            }
            else if (Input.GetKeyDown(KeyCode.Comma) || Input.GetKeyDown(KeyCode.LeftArrow)) // < key or left arrow
            {
                DecreaseTimeSpeed();
            }
            else if (Input.GetKeyDown(KeyCode.Space)) // Space to reset speed
            {
                ResetTimeSpeed();
            }
            else if (Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.C)) // ESC or C to cancel journey
            {
                CancelJourney();
            }
        }

        // Handle map clicking for travel planning (only if click is outside UI panel)
        if (Input.GetMouseButtonDown(0) && !isTraveling)
        {
            // Check if click is within the UI panel bounds
            if (travelUI != null && travelUI.IsVisible && travelUI.IsPointWithinUI(Input.mousePosition))
            {
                return; // Block map interaction if clicking within UI panel
            }

            Vector3 mouseWorldPos = GetMouseWorldPosition();

            if (mouseWorldPos != Vector3.zero)
            {
                Vector2Int clickedTile = WorldToTilePosition(mouseWorldPos);
                PlanTravelTo(clickedTile);
            }
        }

        // Check if TravelUI is blocking other input (non-map clicks)
        if (IsTravelUIBlocking())
        {
            return; // Block other inputs but allow map clicks above
        }

        // Cancel travel planning
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            CancelTravelPlanning();
        }

        // Cycle through route visualizations
        if (Input.GetKeyDown(KeyCode.Tab) && availableRoutes.Count > 1)
        {
            currentRouteIndex = (currentRouteIndex + 1) % availableRoutes.Count;
            var selectedRoute = availableRoutes[currentRouteIndex];

            // Highlight the selected route without clearing others
            HighlightSpecificRoute(selectedRoute);

            // Update the UI to show the new selected route
            if (travelUI != null)
            {
                travelUI.UpdateUIForSelectedRoute(selectedRoute);
            }

            if (showDebugLogs)
            {
                Debug.Log($"Switched to {selectedRoute.routeType} route (Time: {selectedRoute.estimatedTime:F1}h)");
            }
        }

        // Debug key to show movement costs
        if (Input.GetKeyDown(KeyCode.C) && showMovementCosts)
        {
            ShowMovementCostInfo();
        }

        // Toggle debug logs
        if (Input.GetKeyDown(KeyCode.F8))
        {
            showDebugLogs = !showDebugLogs;
            Debug.Log($"Travel System Debug Logs: {(showDebugLogs ? "ENABLED" : "DISABLED")}");
        }
    }

    /// <summary>
    /// Plans travel to the specified destination and shows available routes
    /// </summary>
    public void PlanTravelTo(Vector2Int destination)
    {
        if (!teamPlacement.IsTeamPlaced())
        {
            Debug.LogWarning("❌ Cannot plan travel: Team not placed yet");
            return;
        }

        Vector2Int currentPosition = teamPlacement.GetTeamPosition();

        if (currentPosition == destination)
        {
            Debug.Log("Already at destination!");
            return;
        }

        plannedDestination = destination;
        currentRouteIndex = 0; // Reset route index for new destination

        if (showDebugLogs)
        {
            Debug.Log($"🗺️ Planning travel from {currentPosition} to {destination}");
        }

        // Calculate different route options
        CalculateRoutes(currentPosition, destination);

        // If UI is already visible, refresh it with new routes
        if (travelUI != null && travelUI.IsVisible)
        {
            Debug.Log("🔄 TeamTravelSystem: UI is visible, refreshing with new routes");
            travelUI.RefreshWithNewRoutes(availableRoutes);
        }

        // Show all available routes visually with different colors
        if (availableRoutes.Count > 0)
        {
            // Clear any existing visualizations first
            ClearPathVisualization();

            // Select the fastest route (shortest estimated time) by default
            var routesByTime = availableRoutes.OrderBy(r => r.estimatedTime).ToList();
            TravelRoute selectedRoute = routesByTime.First();

            // Update currentRouteIndex to match the selected route in the original list
            currentRouteIndex = availableRoutes.IndexOf(selectedRoute);

            // Visualize all routes with the fastest one highlighted on top
            VisualizeAllRoutes(availableRoutes);

            if (showDebugLogs)
            {
                Debug.Log($"🔧 About to show UI for {selectedRoute.routeType} route with {selectedRoute.path.Count} waypoints");
            }

            // Show travel UI if available
            ShowTravelUIIfAvailable(destination, availableRoutes);

            if (showDebugLogs)
            {
                Debug.Log($"Found {availableRoutes.Count} route options. Selected {selectedRoute.routeType} route: {selectedRoute.estimatedTime:F1}h time");
                Debug.Log("Use TAB to cycle through different route options");
            }
        }
    }

    /// <summary>
    /// Calculates different route options including fastest, shortest, and cheapest routes
    /// </summary>
    private void CalculateRoutes(Vector2Int start, Vector2Int destination)
    {
        availableRoutes.Clear();

        var mapData = mapMaker.GetMapData();
        if (mapData == null) return;

        if (showDebugLogs)
        {
            Debug.Log($"🔍 Calculating routes from {start} to {destination}");
        }

        // Fastest route (heavily prefers roads and fast terrain)
        var fastestRoute = FindPath(start, destination, RouteType.RoadPreferred);
        if (fastestRoute != null)
        {
            availableRoutes.Add(fastestRoute);
            if (showDebugLogs)
            {
                Debug.Log($"Fastest route: {fastestRoute.estimatedTime:F1}h time, {fastestRoute.path.Count} waypoints");
            }
        }

        // Shortest route (direct path, minimal waypoints)
        var shortestRoute = FindPath(start, destination, RouteType.Standard);
        if (shortestRoute != null)
        {
            bool similar = RoutesSimilar(fastestRoute, shortestRoute);
            if (showDebugLogs)
            {
                Debug.Log($"Shortest route: {shortestRoute.estimatedTime:F1}h time, {shortestRoute.path.Count} waypoints, similar to fastest: {similar}");
            }
            if (!similar)
            {
                availableRoutes.Add(shortestRoute);
            }
        }

        // Cheapest route (minimizes resource costs first, then travel time)
        var cheapestRoute = FindCheapestPath(start, destination);
        if (cheapestRoute != null)
        {
            bool similarToFastest = RoutesSimilar(fastestRoute, cheapestRoute);
            bool similarToShortest = RoutesSimilar(shortestRoute, cheapestRoute);
            if (showDebugLogs)
            {
                Debug.Log($"Cheapest route: {cheapestRoute.estimatedTime:F1}h time, {GetTotalResourceCost(cheapestRoute)} resource cost, {cheapestRoute.path.Count} waypoints");
            }
            if (!similarToFastest && !similarToShortest)
            {
                availableRoutes.Add(cheapestRoute);
            }
        }

        // If we ended up with only one route, try to generate alternatives with different parameters
        if (availableRoutes.Count == 1)
        {
            if (showDebugLogs)
            {
                Debug.Log("Only one unique route found, generating alternatives...");
            }

            // Try a more direct route that ignores some terrain penalties
            var directRoute = FindDirectPath(start, destination);
            if (directRoute != null && !RoutesSimilar(availableRoutes[0], directRoute))
            {
                availableRoutes.Add(directRoute);
                if (showDebugLogs)
                {
                    Debug.Log($"Direct route added: {directRoute.estimatedTime:F1}h time");
                }
            }
        }

        if (showDebugLogs)
        {
            Debug.Log($"📊 Total unique routes calculated: {availableRoutes.Count}");
        }
    }

    /// <summary>
    /// Finds the best path between two points using A* pathfinding with different route preferences
    /// </summary>
    private TravelRoute FindPath(Vector2Int start, Vector2Int destination, RouteType routeType)
    {
        var mapData = mapMaker.GetMapData();
        Debug.Log($"🗺️ Finding {routeType} path from {start} to {destination}");

        var openSet = new List<PathNode>();
        var closedSet = new HashSet<Vector2Int>();
        var allNodes = new Dictionary<Vector2Int, PathNode>();

        var startNode = new PathNode
        {
            position = start,
            gCost = 0,
            hCost = CalculateHeuristic(start, destination, routeType),
            parent = null
        };

        openSet.Add(startNode);
        allNodes[start] = startNode;

        int iterations = 0;
        const int maxIterations = 10000; // Prevent infinite loops

        while (openSet.Count > 0 && iterations < maxIterations)
        {
            iterations++;

            // Find node with lowest fCost
            var currentNode = openSet.OrderBy(n => n.fCost).ThenBy(n => n.hCost).First();
            openSet.Remove(currentNode);
            closedSet.Add(currentNode.position);

            // Reached destination
            if (currentNode.position == destination)
            {
                var route = ReconstructRoute(currentNode, routeType);
                if (showDebugLogs)
                {
                    Debug.Log($"{routeType} path found in {iterations} iterations, final cost: {currentNode.gCost:F1}");
                }

                // Analyze the route composition
                if (showDebugLogs)
                {
                    AnalyzeRouteComposition(route);
                }

                return route;
            }

            // Check neighbors
            var neighbors = GetNeighbors(currentNode.position);
            foreach (var neighbor in neighbors)
            {
                if (closedSet.Contains(neighbor) || !mapData.IsValidPosition(neighbor.x, neighbor.y))
                    continue;

                float movementCost = GetMovementCost(currentNode.position, neighbor, routeType);
                if (movementCost < 0) continue; // Impassable terrain

                float tentativeGCost = currentNode.gCost + movementCost;

                if (!allNodes.ContainsKey(neighbor))
                {
                    allNodes[neighbor] = new PathNode
                    {
                        position = neighbor,
                        gCost = float.MaxValue,
                        hCost = CalculateHeuristic(neighbor, destination, routeType),
                        parent = null
                    };
                }

                var neighborNode = allNodes[neighbor];

                if (tentativeGCost < neighborNode.gCost)
                {
                    neighborNode.parent = currentNode;
                    neighborNode.gCost = tentativeGCost;

                    if (!openSet.Contains(neighborNode))
                    {
                        openSet.Add(neighborNode);
                    }
                }
            }
        }

        Debug.LogWarning($"❌ {routeType} path not found after {iterations} iterations (max: {maxIterations})");
        return null; // No path found
    }

    /// <summary>
    /// Gets movement cost for moving from one tile to another, considering route type preferences
    /// </summary>
    private float GetMovementCost(Vector2Int from, Vector2Int to, RouteType routeType)
    {
        var mapData = mapMaker.GetMapData();
        var toTile = mapData.GetTile(to.x, to.y);

        // Base movement cost by terrain
        float baseCost = GetTerrainMovementCost(toTile);

        // Feature modifications
        float featureCost = GetFeatureMovementCost(toTile, routeType);

        // Combine costs
        float totalCost = baseCost * featureCost;

        // Route type adjustments
        switch (routeType)
        {
            case RouteType.Standard:
                // Shortest route: minimize distance regardless of terrain difficulty
                // No terrain or road preferences - pure distance optimization
                break;

            case RouteType.RoadPreferred:
                // Fastest route: heavily favors roads and fast terrain, considers costly but fast options
                if (toTile.featureType == FeatureType.Road)
                {
                    totalCost *= 0.3f; // Strong road preference (70% discount) - roads are much faster but realistic
                }
                else if (toTile.featureType == FeatureType.Tunnel)
                {
                    // Tunnels are fast for fastest route (ignore resource cost for speed optimization)
                    totalCost *= 0.4f; // Very fast travel through tunnels
                }
                else if (toTile.featureType == FeatureType.Ferry)
                {
                    // Ferries are reasonably fast for fastest route
                    totalCost *= 0.6f; // Fast water crossing
                }
                else
                {
                    // Penalize non-road movement for road-preferred routes
                    totalCost *= 1.5f; // 50% penalty for off-road movement
                }
                break;

            case RouteType.Special:
                // Cheapest route: avoid resource costs, but don't make travel time unrealistic
                // Moderate penalties for features that cost resources
                if (toTile.featureType == FeatureType.Ferry || toTile.featureType == FeatureType.Tunnel)
                    totalCost *= 3.0f; // Significant penalty for resource-costing features (was 10x)

                // Moderate penalties for features that might trigger resource costs
                if (toTile.featureType == FeatureType.Bridge)
                    totalCost *= 2.0f; // Penalty for bridges (potential tolls) (was 5x)

                // Light penalty for terrain that requires guides/special costs
                if (toTile.terrainType == TerrainType.Mountain)
                    totalCost *= 2.0f; // Penalty for mountains (guide costs) (was 5x)

                // Still avoid slow terrain, but secondary to cost avoidance
                if (toTile.terrainType == TerrainType.River || toTile.terrainType == TerrainType.Lake)
                    totalCost *= 1.5f; // Light penalty for water crossings (was 2x)

                // Prefer roads since they're free and fast
                if (toTile.featureType == FeatureType.Road)
                    totalCost *= 0.5f; // Good road preference (50% discount)
                break;
        }

        return totalCost;
    }

    /// <summary>
    /// Gets base movement cost for different terrain types
    /// </summary>
    private float GetTerrainMovementCost(MapTile tile)
    {
        switch (tile.terrainType)
        {
            case TerrainType.Plains:
                return plainsMovementCost;
            case TerrainType.Forest:
                return forestMovementCost;
            case TerrainType.Mountain:
                return mountainMovementCost;
            case TerrainType.Ocean:
                return oceanCrossingCost; // Allow dangerous ocean crossing
            case TerrainType.Lake:
                return lakeCrossingCost; // Allow swimming across lakes
            case TerrainType.River:
                return riverCrossingCost; // Allow slow river crossing
            default:
                return plainsMovementCost;
        }
    }

    /// <summary>
    /// Gets movement cost modifications from features (roads, bridges, etc.)
    /// </summary>
    private float GetFeatureMovementCost(MapTile tile, RouteType routeType)
    {
        switch (tile.featureType)
        {
            case FeatureType.Road:
                return roadMovementCost; // Fast movement on roads
            case FeatureType.Bridge:
                return roadMovementCost; // Bridges are as fast as roads (crossing structures)
            case FeatureType.Town:
            case FeatureType.Village:
                return townMovementCost; // Very fast through settlements
            case FeatureType.Ferry:
                return ferryMovementCost; // Ferries are fast transportation (cost is in gold, not time)
            case FeatureType.Tunnel:
                return tunnelWithTorchCost; // Tunnels are fast with torch (cost is in torches, not time)
            default:
                return 1f; // No modification
        }
    }

    /// <summary>
    /// Calculates heuristic distance for A* pathfinding with route type considerations
    /// </summary>
    private float CalculateHeuristic(Vector2Int from, Vector2Int to, RouteType routeType = RouteType.Standard)
    {
        float baseHeuristic = Vector2Int.Distance(from, to) * plainsMovementCost;

        // For road-preferred routes, make the heuristic slightly more optimistic about finding roads
        if (routeType == RouteType.RoadPreferred)
        {
            // Assume we'll find roads for some of the journey
            baseHeuristic *= 0.8f; // Slightly more optimistic heuristic
        }

        return baseHeuristic;
    }

    /// <summary>
    /// Gets valid neighboring tiles for pathfinding
    /// </summary>
    private List<Vector2Int> GetNeighbors(Vector2Int position)
    {
        var neighbors = new List<Vector2Int>();

        // 8-directional movement
        for (int dx = -1; dx <= 1; dx++)
        {
            for (int dy = -1; dy <= 1; dy++)
            {
                if (dx == 0 && dy == 0) continue;

                Vector2Int neighbor = new Vector2Int(position.x + dx, position.y + dy);
                neighbors.Add(neighbor);
            }
        }

        return neighbors;
    }

    /// <summary>
    /// Reconstructs the final route from pathfinding results
    /// </summary>
    private TravelRoute ReconstructRoute(PathNode destinationNode, RouteType routeType)
    {
        var route = new TravelRoute
        {
            routeType = routeType,
            path = new List<Vector2Int>(),
            totalCost = destinationNode.gCost,
            totalDistance = 0f,
            estimatedTime = 0f,
            specialCosts = new Dictionary<string, int>()
        };

        var current = destinationNode;
        while (current != null)
        {
            route.path.Insert(0, current.position);
            current = current.parent;
        }

        // Calculate additional route information
        CalculateRouteDetails(route);

        return route;
    }

    /// <summary>
    /// Finds a more direct path that ignores some terrain penalties for route variety
    /// </summary>
    private TravelRoute FindDirectPath(Vector2Int start, Vector2Int destination)
    {
        var mapData = mapMaker.GetMapData();
        Debug.Log($"🎯 Finding direct path from {start} to {destination}");

        var openSet = new List<PathNode>();
        var closedSet = new HashSet<Vector2Int>();
        var allNodes = new Dictionary<Vector2Int, PathNode>();

        var startNode = new PathNode
        {
            position = start,
            gCost = 0,
            hCost = CalculateHeuristic(start, destination),
            parent = null
        };

        openSet.Add(startNode);
        allNodes[start] = startNode;

        int iterations = 0;
        const int maxIterations = 10000;

        while (openSet.Count > 0 && iterations < maxIterations)
        {
            iterations++;

            var currentNode = openSet.OrderBy(n => n.fCost).ThenBy(n => n.hCost).First();
            openSet.Remove(currentNode);
            closedSet.Add(currentNode.position);

            if (currentNode.position == destination)
            {
                var route = ReconstructRoute(currentNode, RouteType.Special);
                route.routeType = RouteType.Special; // Mark as direct route
                Debug.Log($"✅ Direct path found in {iterations} iterations, final cost: {currentNode.gCost:F1}");
                CalculateRouteDetails(route);
                return route;
            }

            var neighbors = GetNeighbors(currentNode.position);
            foreach (var neighbor in neighbors)
            {
                if (closedSet.Contains(neighbor) || !mapData.IsValidPosition(neighbor.x, neighbor.y))
                    continue;

                // Use simplified movement cost for direct routes (less terrain penalty)
                float movementCost = GetDirectMovementCost(currentNode.position, neighbor);
                if (movementCost < 0) continue;

                float tentativeGCost = currentNode.gCost + movementCost;

                if (!allNodes.ContainsKey(neighbor))
                {
                    allNodes[neighbor] = new PathNode
                    {
                        position = neighbor,
                        gCost = float.MaxValue,
                        hCost = CalculateHeuristic(neighbor, destination),
                        parent = null
                    };
                }

                var neighborNode = allNodes[neighbor];

                if (tentativeGCost < neighborNode.gCost)
                {
                    neighborNode.parent = currentNode;
                    neighborNode.gCost = tentativeGCost;

                    if (!openSet.Contains(neighborNode))
                    {
                        openSet.Add(neighborNode);
                    }
                }
            }
        }

        Debug.LogWarning($"❌ Direct path not found after {iterations} iterations");
        return null;
    }

    /// <summary>
    /// Simplified movement cost calculation for direct routes
    /// </summary>
    private float GetDirectMovementCost(Vector2Int from, Vector2Int to)
    {
        var mapData = mapMaker.GetMapData();
        var toTile = mapData.GetTile(to.x, to.y);

        // Simplified costs that emphasize directness over terrain optimization
        switch (toTile.terrainType)
        {
            case TerrainType.Plains:
                return 1.0f;
            case TerrainType.Forest:
                return 1.5f; // Less penalty than normal
            case TerrainType.Mountain:
                return 2.0f; // Much less penalty for directness
            case TerrainType.River:
                return 1.8f;
            case TerrainType.Lake:
                return 2.0f;
            case TerrainType.Ocean:
                return 4.0f; // Still expensive but possible
            default:
                return 1.0f;
        }
    }

    /// <summary>
    /// Finds the cheapest path that minimizes resource costs (gold) first, then travel time
    /// Uses the Special route type but should calculate actual travel time correctly
    /// </summary>
    private TravelRoute FindCheapestPath(Vector2Int start, Vector2Int destination)
    {
        // Use the standard A* pathfinding with Special route type (which avoids costly features)
        return FindPath(start, destination, RouteType.Special);
    }

    /// <summary>
    /// Gets the resource cost for entering a specific tile
    /// </summary>
    private float GetResourceCostForTile(Vector2Int position)
    {
        var mapData = mapMaker.GetMapData();
        var tile = mapData.GetTile(position.x, position.y);

        switch (tile.featureType)
        {
            case FeatureType.Ferry:
                return ferryBaseCost; // Direct gold cost
            case FeatureType.Tunnel:
                return tunnelTorchCost; // Torch cost (treated as gold equivalent)
            case FeatureType.Bridge:
                return 2.0f; // Potential bridge toll (small cost to prefer other routes)
            default:
                break;
        }

        // Terrain-based resource costs (for guide fees, etc.)
        switch (tile.terrainType)
        {
            case TerrainType.Mountain:
                return 3.0f; // Potential guide cost for dangerous areas
            default:
                return 0.0f; // No resource cost
        }
    }

    /// <summary>
    /// Calculates detailed information about the route (distance, time, special costs)
    /// </summary>
    private void CalculateRouteDetails(TravelRoute route)
    {
        var mapData = mapMaker.GetMapData();

        route.totalDistance = route.path.Count;
        route.estimatedTime = route.totalCost * 0.5f; // Rough time estimate

        // Check for special costs
        int bridgeCount = 0;
        int mountainTileCount = 0;

        foreach (var position in route.path)
        {
            var tile = mapData.GetTile(position.x, position.y);

            // Ferry costs
            if (tile.featureType == FeatureType.Ferry)
            {
                if (!route.specialCosts.ContainsKey("Ferry"))
                    route.specialCosts["Ferry"] = ferryBaseCost;
            }
            // Tunnel costs
            else if (tile.featureType == FeatureType.Tunnel)
            {
                if (!route.specialCosts.ContainsKey("Tunnel Torch"))
                    route.specialCosts["Tunnel Torch"] = tunnelTorchCost;
            }
            // Bridge tolls (for major bridges)
            else if (tile.featureType == FeatureType.Bridge)
            {
                bridgeCount++;
            }
            // Mountain passes (dangerous mountain areas need guides)
            else if (tile.terrainType == TerrainType.Mountain)
            {
                mountainTileCount++;
            }
        }

        // Add bridge toll costs (only for longer bridge crossings)
        if (bridgeCount >= 3) // Only charge for significant bridge crossings
        {
            route.specialCosts["Bridge Toll"] = bridgeTollCost;
        }

        // Add mountain guide costs (for extensive mountain travel)
        if (mountainTileCount >= 5) // Only charge for dangerous mountain passes
        {
            route.specialCosts["Mountain Guide"] = mountainPassCost;
        }
    }

    /// <summary>
    /// Calculates the total resource cost (gold equivalent) for a route
    /// </summary>
    private int GetTotalResourceCost(TravelRoute route)
    {
        if (route?.specialCosts == null) return 0;

        int totalCost = 0;
        foreach (var cost in route.specialCosts)
        {
            totalCost += cost.Value; // All costs are in gold or gold-equivalent
        }
        return totalCost;
    }

    /// <summary>
    /// Checks if two routes are essentially the same
    /// </summary>
    private bool RoutesSimilar(TravelRoute route1, TravelRoute route2)
    {
        if (route1 == null || route2 == null) return false;

        // Consider routes similar if they have >90% path overlap (more strict to allow more variations)
        var overlap = route1.path.Intersect(route2.path).Count();
        var maxLength = Mathf.Max(route1.path.Count, route2.path.Count);

        bool similar = (float)overlap / maxLength > 0.9f;
        Debug.Log($"🔍 Route similarity check: {overlap}/{maxLength} = {((float)overlap / maxLength):F2} > 0.9? {similar}");

        return similar;
    }

    /// <summary>
    /// Analyzes and logs the composition of a route for debugging
    /// </summary>
    private void AnalyzeRouteComposition(TravelRoute route)
    {
        if (route == null || route.path == null) return;

        var mapData = mapMaker.GetMapData();
        int plainsCount = 0, forestCount = 0, mountainCount = 0, roadCount = 0, riverCount = 0, lakeCount = 0;
        float totalMovementCost = 0;
        float roadBonusTotal = 0;

        foreach (var pos in route.path)
        {
            var tile = mapData.GetTile(pos.x, pos.y);
            float tileCost = GetMovementCost(pos, pos, route.routeType);
            totalMovementCost += tileCost;

            switch (tile.terrainType)
            {
                case TerrainType.Plains: plainsCount++; break;
                case TerrainType.Forest: forestCount++; break;
                case TerrainType.Mountain: mountainCount++; break;
                case TerrainType.River: riverCount++; break;
                case TerrainType.Lake: lakeCount++; break;
            }

            if (tile.featureType == FeatureType.Road)
            {
                roadCount++;
                // Calculate road bonus for this route type
                switch (route.routeType)
                {
                    case RouteType.Standard:
                        roadBonusTotal += GetTerrainMovementCost(tile) * (1f - 0.6f); // 40% discount
                        break;
                    case RouteType.RoadPreferred:
                        roadBonusTotal += GetTerrainMovementCost(tile) * (1f - 0.2f); // 80% discount
                        break;
                }
            }
        }

        float avgCostPerTile = totalMovementCost / route.path.Count;
        float roadPercentage = (float)roadCount / route.path.Count * 100f;

        Debug.Log($"📊 Route Analysis ({route.routeType}): {route.path.Count} tiles");
        Debug.Log($"   Terrain: Plains:{plainsCount}, Forest:{forestCount}, Mountain:{mountainCount}, Rivers:{riverCount}, Lakes:{lakeCount}");
        Debug.Log($"   Roads: {roadCount} tiles ({roadPercentage:F1}%), saved {roadBonusTotal:F1} cost");
        Debug.Log($"   Average cost per tile: {avgCostPerTile:F2} (Total: {totalMovementCost:F1})");
        Debug.Log($"   Time calculation: {route.estimatedTime:F1}h = {route.totalCost:F1} cost × 0.5 multiplier");

        // Explain why this route type might be different
        string explanation = "";
        switch (route.routeType)
        {
            case RouteType.Standard:
                explanation = "Shortest route minimizes distance and waypoints";
                break;
            case RouteType.RoadPreferred:
                explanation = $"Fastest route heavily favors roads (90% discount) - {roadPercentage:F1}% on roads";
                break;
            case RouteType.Special:
                explanation = "Cheapest/Direct route avoids special costs and takes direct paths";
                break;
        }
        Debug.Log($"   Strategy: {explanation}");
    }

    /// <summary>
    /// Visualizes the selected route on the map
    /// </summary>
    private void VisualizeRoute(TravelRoute route)
    {
        if (showDebugLogs)
        {
            Debug.Log($"🎨 VisualizeRoute called with route: {route?.routeType} ({route?.path?.Count ?? 0} points)");
        }

        ClearPathVisualization();

        if (route == null || route.path.Count == 0)
        {
            if (showDebugLogs)
            {
                Debug.LogWarning("❌ Cannot visualize route: route is null or has no path points");
            }
            return;
        }

        // Create path visualization
        var pathObject = new GameObject("TravelPath");
        var lineRenderer = pathObject.AddComponent<LineRenderer>();

        // Configure line renderer with simple, reliable settings
        lineRenderer.material = pathLineMaterial ?? CreateDefaultPathMaterial();
        lineRenderer.material.color = GetRouteColor(route);

        // Force line width to 1.0 for consistent visibility
        lineRenderer.startWidth = 1.0f;
        lineRenderer.endWidth = 1.0f;
        lineRenderer.positionCount = route.path.Count;
        lineRenderer.useWorldSpace = true;

        // Simple LineRenderer settings for reliable visibility
        lineRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        lineRenderer.receiveShadows = false;
        lineRenderer.alignment = LineAlignment.View; // Face camera
        lineRenderer.textureMode = LineTextureMode.Tile;
        lineRenderer.sortingLayerName = "Default";
        lineRenderer.sortingOrder = 50; // High sorting order but not excessive

        // Debug the width setting
        if (showDebugLogs)
        {
            Debug.Log($"🔧 Setting LineRenderer width to: {pathLineWidth} (startWidth: {lineRenderer.startWidth}, endWidth: {lineRenderer.endWidth})");
        }

        // Set path points
        for (int i = 0; i < route.path.Count; i++)
        {
            Vector3 worldPos = TileToWorldPosition(route.path[i]);
            worldPos.y = pathLineHeight; // Place above map tiles
            lineRenderer.SetPosition(i, worldPos);
        }

        currentPathVisualizations.Add(pathObject);

        if (showDebugLogs)
        {
            Debug.Log($"📍 Visualized {route.routeType} route with {route.path.Count} waypoints");
            Debug.Log($"🔧 LineRenderer config: startWidth={lineRenderer.startWidth}, endWidth={lineRenderer.endWidth}, material={lineRenderer.material?.name}, color={lineRenderer.material?.color}");
            Debug.Log($"🎯 GameObject created: {pathObject.name} at position {pathObject.transform.position}");
        }
    }

    /// <summary>
    /// Visualizes all available routes with different colors and proper layering
    /// </summary>
    private void VisualizeAllRoutes(List<TravelRoute> routes)
    {
        ClearPathVisualization();

        // Render all routes with the first one (fastest by time) selected by default
        var routesByTime = routes.OrderBy(r => r.estimatedTime).ToList();
        var defaultSelected = routesByTime.FirstOrDefault();

        for (int i = 0; i < routes.Count; i++)
        {
            var route = routes[i];
            if (route == null || route.path.Count == 0) continue;

            bool isSelected = (route == defaultSelected);
            RenderSingleRoute(route, i, isSelected);
        }

        if (showDebugLogs)
        {
            string selectedName = defaultSelected?.routeType == RouteType.RoadPreferred ? "Fastest" :
                                 defaultSelected?.routeType == RouteType.Standard ? "Shortest" : "Cheapest";
            Debug.Log($"🎨 Visualized {routes.Count} routes with {selectedName} as default selected (on top)");
        }
    }    /// <summary>
         /// Gets the appropriate color for a route based on its type (GPS-style)
         /// </summary>
    private Color GetRouteColor(TravelRoute route)
    {
        // GPS-style color coding
        switch (route.routeType)
        {
            case RouteType.RoadPreferred: // Fastest route
                if (showDebugLogs) Debug.Log($"🎨 Route color: GREEN (fastest route)");
                return Color.green; // Green for fastest (like GPS)

            case RouteType.Standard: // Shortest route
                if (showDebugLogs) Debug.Log($"🎨 Route color: BLUE (shortest route)");
                return standardPathColor; // Blue for shortest

            case RouteType.Special: // Cheapest/Direct route
                if (showDebugLogs) Debug.Log($"🎨 Route color: YELLOW (cheapest/direct route)");
                return alternativePathColor; // Yellow for cheapest/alternative

            default:
                if (showDebugLogs) Debug.Log($"🎨 Route color: BLUE (default)");
                return standardPathColor;
        }
    }

    /// <summary>
    /// Creates a default material for path visualization
    /// </summary>
    private Material CreateDefaultPathMaterial()
    {
        // Use simple Sprites/Default shader for reliable rendering
        Shader shader = Shader.Find("Sprites/Default");
        if (shader == null)
            shader = Shader.Find("Legacy Shaders/Particles/Alpha Blended Premultiply");
        if (shader == null)
            shader = Shader.Find("Unlit/Color");
        if (shader == null)
            shader = Shader.Find("Standard");

        var material = new Material(shader ?? Shader.Find("Diffuse"));
        material.color = standardPathColor;

        if (showDebugLogs)
        {
            Debug.Log($"🎨 Created path material with shader: {shader?.name ?? "Unknown"}");
        }

        return material;
    }

    /// <summary>
    /// Clears any existing path visualization
    /// </summary>
    private void ClearPathVisualization()
    {
        foreach (var pathViz in currentPathVisualizations)
        {
            if (pathViz != null)
            {
                DestroyImmediate(pathViz);
            }
        }
        currentPathVisualizations.Clear();
    }

    /// <summary>
    /// Cancels current travel planning
    /// </summary>
    public void CancelTravelPlanning()
    {
        plannedDestination = null;
        availableRoutes.Clear();
        ClearPathVisualization();
        HideTravelUI();

        if (showDebugLogs)
        {
            Debug.Log("❌ Travel planning cancelled");
        }
    }

    /// <summary>
    /// Starts travel using the specified route
    /// </summary>
    public void StartTravel(TravelRoute route)
    {
        if (route == null || isTraveling)
        {
            Debug.LogWarning("Cannot start travel: invalid route or already traveling");
            return;
        }

        // Synchronize coordinates before starting travel
        SynchronizeWithExplorationSystem();

        // Reset cancellation flag and store current route
        shouldCancelJourney = false;
        currentRoute = route;

        // Start the travel coroutine and store reference
        currentTravelCoroutine = StartCoroutine(ExecuteTravel(route));
    }

    /// <summary>
    /// Cancels the current journey if one is in progress
    /// </summary>
    public void CancelJourney()
    {
        if (!isTraveling)
        {
            if (showDebugLogs) Debug.Log("No journey to cancel");
            return;
        }

        if (showDebugLogs)
        {
            Debug.Log("Journey cancellation requested by player");
        }

        // Set the cancellation flag
        shouldCancelJourney = true;

        // The actual cleanup will happen in the ExecuteTravel coroutine
    }

    /// <summary>
    /// Executes the actual travel along the route
    /// </summary>
    private IEnumerator ExecuteTravel(TravelRoute route)
    {
        isTraveling = true;

        if (showDebugLogs)
        {
            Debug.Log($"🚶 Starting travel along {route.routeType} route");
            Debug.Log($"📍 Route has {route.path.Count} waypoints, estimated time: {route.estimatedTime:F1} hours");
        }

        // Ensure team marker is visible during travel (stop blinking)
        EnsureTeamMarkerVisible(true);

        // Debug: Check initial team marker state
        var initialMarker = teamPlacement.GetTeamMarker();
        if (initialMarker != null)
        {
            Debug.Log($"🔍 Initial team marker: Position={initialMarker.transform.position}, Active={initialMarker.activeInHierarchy}, WorldPos={initialMarker.transform.position}");
            var initialRenderer = initialMarker.GetComponent<Renderer>();
            if (initialRenderer != null)
            {
                Debug.Log($"🔍 Initial renderer: Enabled={initialRenderer.enabled}, Material={initialRenderer.material?.name}");
            }
        }
        else
        {
            Debug.LogError("❌ No team marker found at start of travel!");
        }

        // Deduct special costs before travel
        DeductTravelCosts(route);

        // Move team marker along the path with smooth animation
        for (int i = 1; i < route.path.Count; i++)
        {
            // Check for cancellation at the start of each step
            if (shouldCancelJourney)
            {
                if (showDebugLogs)
                {
                    Debug.Log($"🛑 Journey cancelled at step {i}/{route.path.Count - 1}. Stopping at {route.path[i - 1]}");
                }
                break; // Exit the movement loop
            }

            Vector2Int nextPosition = route.path[i];
            Vector2Int currentPos = route.path[i - 1];

            if (showDebugLogs && i % 3 == 0) // Log every 3rd step
            {
                Debug.Log($"🚶 Traveling step {i}/{route.path.Count - 1} to {nextPosition} ({((float)i / (route.path.Count - 1) * 100):F0}% complete)");
            }

            // Get current and target world positions for smooth movement
            Vector3 currentWorldPos = TileToWorldPosition(currentPos);
            Vector3 targetWorldPos = TileToWorldPosition(nextPosition);

            // Animate the team marker moving smoothly between positions
            float moveTime = 0.8f; // Base time per step (slower movement)
            float stepCost = GetMovementCost(currentPos, nextPosition, route.routeType);

            // Adjust move time based on terrain difficulty
            moveTime *= Mathf.Clamp(stepCost * 0.3f, 0.5f, 3f); // Slower for difficult terrain

            // Smooth movement animation
            float elapsed = 0f;
            while (elapsed < moveTime)
            {
                // Check for cancellation during movement animation
                if (shouldCancelJourney)
                {
                    if (showDebugLogs)
                    {
                        Debug.Log($"🛑 Journey cancelled during movement animation. Stopping at current position.");
                    }
                    break; // Exit the animation loop
                }

                elapsed += Time.deltaTime;
                float t = Mathf.SmoothStep(0f, 1f, elapsed / moveTime);

                // Interpolate between current and target position
                Vector3 lerpedWorldPos = Vector3.Lerp(currentWorldPos, targetWorldPos, t);
                Vector2Int lerpedTilePos = WorldToTilePosition(lerpedWorldPos);

                // Update team position smoothly (but only if it's a valid position)
                if (mapMaker.GetMapData().IsValidPosition(lerpedTilePos.x, lerpedTilePos.y))
                {
                    teamPlacement.PlaceTeamAt(lerpedTilePos);

                    // Ensure marker stays visible during travel
                    var teamMarker = teamPlacement.GetTeamMarker();
                    if (teamMarker != null)
                    {
                        teamMarker.SetActive(true);
                        var renderer = teamMarker.GetComponent<Renderer>();
                        if (renderer != null && !renderer.enabled)
                        {
                            renderer.enabled = true;
                            if (showDebugLogs)
                            {
                                Debug.Log($"🔧 Re-enabled team marker renderer at {teamMarker.transform.position}");
                            }
                        }
                    }
                }

                yield return null; // Wait one frame
            }

            // Break out of the inner animation loop if cancelled
            if (shouldCancelJourney)
            {
                break; // Exit the for loop as well
            }

            // Ensure we end up exactly at the target position (if not cancelled)
            if (!shouldCancelJourney)
            {
                teamPlacement.PlaceTeamAt(nextPosition);
            }
        }

        // Journey cleanup - whether completed or cancelled
        isTraveling = false;
        ResetTimeSpeed(); // Reset time scale to normal when travel ends
        EnsureTeamMarkerVisible(false); // Restore blinking
        ClearPathVisualization();
        HideTravelUI();

        // Synchronize coordinate systems after travel
        SynchronizeWithExplorationSystem();

        // Clear travel state
        currentTravelCoroutine = null;
        currentRoute = null;

        if (shouldCancelJourney)
        {
            if (showDebugLogs)
            {
                Debug.Log($"🛑 Journey cancelled! Team stopped at {teamPlacement.GetTeamPosition()}");
            }
            shouldCancelJourney = false; // Reset the flag
        }
        else
        {
            if (showDebugLogs)
            {
                Debug.Log($"✅ Travel completed! Arrived at {route.path.Last()}");
            }
        }
    }

    /// <summary>
    /// Synchronize travel system coordinates with exploration system
    /// </summary>
    private void SynchronizeWithExplorationSystem()
    {
        if (mapMaker != null && mapMaker.useExplorationSystem)
        {
            mapMaker.SyncTeamPosition();
            if (showDebugLogs)
            {
                Debug.Log("🔄 Synchronized team position with exploration system");
            }
        }
    }

    /// <summary>
    /// Deducts costs for travel (gold, items, etc.)
    /// </summary>
    private void DeductTravelCosts(TravelRoute route)
    {
        if (route.specialCosts.Count == 0) return;

        if (showDebugLogs)
        {
            Debug.Log($"💰 Deducting travel costs: {string.Join(", ", route.specialCosts.Select(kvp => $"{kvp.Key}: {kvp.Value}"))}");
        }

        // TODO: Implement actual resource deduction
        // This would integrate with your inventory/currency system
        foreach (var cost in route.specialCosts)
        {
            switch (cost.Key)
            {
                case "Ferry":
                    // DeductGold(cost.Value);
                    Debug.Log($"💰 Would deduct {cost.Value} gold for ferry");
                    break;
                case "Tunnel Torch":
                    // DeductTorches(cost.Value);
                    Debug.Log($"🔥 Would deduct {cost.Value} torches for tunnel");
                    break;
            }
        }
    }

    /// <summary>
    /// Ensures the team marker is visible during travel by controlling its blinking behavior
    /// </summary>
    private void EnsureTeamMarkerVisible(bool forceVisible)
    {
        if (teamPlacement == null)
        {
            Debug.LogWarning("❌ TeamPlacement is null in EnsureTeamMarkerVisible");
            return;
        }

        var teamMarker = teamPlacement.GetTeamMarker();
        if (teamMarker == null)
        {
            Debug.LogWarning("❌ Team marker is null - creating new marker");
            // Force creation of a new marker if it doesn't exist
            teamPlacement.PlaceTeamAt(teamPlacement.GetTeamPosition());
            teamMarker = teamPlacement.GetTeamMarker();
            if (teamMarker == null)
            {
                Debug.LogError("❌ Failed to create team marker!");
                return;
            }
        }

        var renderer = teamMarker.GetComponent<Renderer>();
        if (renderer == null)
        {
            Debug.LogWarning("❌ Team marker has no Renderer component");
            return;
        }

        Debug.Log($"🔧 Team marker status: Position={teamMarker.transform.position}, Active={teamMarker.activeInHierarchy}, RendererEnabled={renderer.enabled}");

        if (forceVisible)
        {
            // Force marker to be visible and stop blinking during travel
            teamMarker.SetActive(true);
            renderer.enabled = true;

            // Make the marker more visible by adjusting its properties
            teamMarker.transform.localScale = Vector3.one * 2f; // Make it bigger

            // Try to change material color to bright red for visibility
            var material = renderer.material;
            if (material != null)
            {
                material.color = Color.red;
                if (material.HasProperty("_BaseColor"))
                    material.SetColor("_BaseColor", Color.red);
                if (material.HasProperty("_Color"))
                    material.SetColor("_Color", Color.red);
                Debug.Log($"🔴 Set team marker to bright red for visibility");
            }

            // Force position to be visible above map (adjust Y for top-down view)
            var pos = teamMarker.transform.position;
            teamMarker.transform.position = new Vector3(pos.x, 2f, pos.z); // Raise above map for visibility

            // Stop any blinking coroutines in SimpleTeamPlacement using reflection
            try
            {
                var placementType = teamPlacement.GetType();
                var stopCooroutinesMethod = placementType.GetMethod("StopAllCoroutines");
                if (stopCooroutinesMethod != null)
                {
                    stopCooroutinesMethod.Invoke(teamPlacement, null);
                    Debug.Log("✅ Stopped blinking coroutines");
                }

                // Set isBlinking to false using reflection
                var isBlinkingField = placementType.GetField("isBlinking", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                if (isBlinkingField != null)
                {
                    isBlinkingField.SetValue(teamPlacement, false);
                    Debug.Log("✅ Set isBlinking to false");
                }
            }
            catch (System.Exception e)
            {
                Debug.LogWarning($"⚠️ Reflection failed: {e.Message}");
            }

            if (showDebugLogs)
            {
                Debug.Log($"👁️ Team marker forced visible for travel at {teamMarker.transform.position}");
            }
        }
        else
        {
            // Restore normal blinking behavior after travel
            try
            {
                var placementType = teamPlacement.GetType();
                var enableBlinkingField = placementType.GetField("enableBlinking", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);

                if (enableBlinkingField != null && (bool)enableBlinkingField.GetValue(teamPlacement))
                {
                    // Restart blinking using reflection
                    var startBlinkingMethod = placementType.GetMethod("StartBlinking", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                    if (startBlinkingMethod != null)
                    {
                        startBlinkingMethod.Invoke(teamPlacement, null);
                        if (showDebugLogs)
                        {
                            Debug.Log("✨ Team marker blinking restored after travel");
                        }
                    }
                }
            }
            catch (System.Exception e)
            {
                Debug.LogWarning($"⚠️ Reflection failed during restore: {e.Message}");
            }
        }
    }

    /// <summary>
    /// Utility methods for coordinate conversion
    /// </summary>
    private Vector3 GetMouseWorldPosition()
    {
        if (mapCamera == null)
        {
            if (showDebugLogs) Debug.LogWarning("❌ Map camera is null, trying to find Camera.main");
            mapCamera = Camera.main;
            if (mapCamera == null) return Vector3.zero;
        }

        Ray ray = mapCamera.ScreenPointToRay(Input.mousePosition);
        if (showDebugLogs) Debug.Log($"📐 Raycast from camera: {ray.origin} direction: {ray.direction}");

        // Try raycast first (if there are colliders)
        if (Physics.Raycast(ray, out RaycastHit hit, 1000f))
        {
            if (showDebugLogs) Debug.Log($"🎯 Raycast hit: {hit.point} on {hit.collider.name}");
            return hit.point;
        }

        // Fallback: use camera plane projection at Y=0 (map level) for top-down view
        Plane mapPlane = new Plane(Vector3.up, Vector3.zero); // Y=0 plane facing up for top-down camera
        if (mapPlane.Raycast(ray, out float distance))
        {
            Vector3 point = ray.GetPoint(distance);
            if (showDebugLogs) Debug.Log($"📍 Plane intersection: {point}");
            return point;
        }

        if (showDebugLogs) Debug.LogWarning("❌ No raycast hit and no plane intersection");
        return Vector3.zero;
    }

    private Vector2Int WorldToTilePosition(Vector3 worldPos)
    {
        float tileSize = mapMaker?.mapVisualizer?.tileSize ?? 1f;
        return new Vector2Int(
            Mathf.RoundToInt(worldPos.x / tileSize),
            Mathf.RoundToInt(worldPos.z / tileSize) // Use Z coordinate for map Y in top-down view
        );
    }

    private Vector3 TileToWorldPosition(Vector2Int tilePos)
    {
        float tileSize = mapMaker?.mapVisualizer?.tileSize ?? 1f;
        return new Vector3(
            tilePos.x * tileSize,
            0f, // Y=0 for tiles at ground level
            tilePos.y * tileSize // Map Y coordinate becomes world Z coordinate for top-down view
        );
    }

    /// <summary>
    /// Debug method to show movement cost information
    /// </summary>
    private void ShowMovementCostInfo()
    {
        Debug.Log("=== MOVEMENT COST INFO ===");
        Debug.Log("TERRAIN COSTS:");
        Debug.Log($"  Plains: {plainsMovementCost}x");
        Debug.Log($"  Forest: {forestMovementCost}x");
        Debug.Log($"  Mountain: {mountainMovementCost}x");
        Debug.Log($"  River Crossing: {riverCrossingCost}x (slow crossing)");
        Debug.Log($"  Lake Swimming: {lakeCrossingCost}x (swimming)");
        Debug.Log($"  Ocean Crossing: {oceanCrossingCost}x (very dangerous)");
        Debug.Log("FEATURE COSTS:");
        Debug.Log($"  Road: {roadMovementCost}x");
        Debug.Log($"  Town/Village: {townMovementCost}x");
        Debug.Log($"  Bridge: {bridgeMovementCost}x");
        Debug.Log($"  Ferry: {ferryMovementCost}x (+ {ferryBaseCost} gold)");
        Debug.Log($"  Tunnel (with torch): {tunnelWithTorchCost}x (+ {tunnelTorchCost} torches)");
        Debug.Log($"  Tunnel (without torch): {tunnelWithoutTorchCost}x");
        Debug.Log("CONTROLS:");
        Debug.Log("  TAB: Cycle through route options");
        Debug.Log("  ESC: Cancel travel planning (or cancel journey if traveling)");
        Debug.Log("  C: Cancel journey while traveling");
        Debug.Log("  F8: Toggle debug logs");
        Debug.Log("TRAVEL CONTROLS (while traveling):");
        Debug.Log("  >,→: Increase travel speed");
        Debug.Log("  <,←: Decrease travel speed");
        Debug.Log("  Space: Reset travel speed to normal");
        Debug.Log("========================");
    }

    /// <summary>
    /// Public getters for external systems
    /// </summary>
    public List<TravelRoute> GetAvailableRoutes() => availableRoutes;
    public Vector2Int? GetPlannedDestination() => plannedDestination;
    public bool IsTraveling() => isTraveling;
    public bool CanCancelJourney() => isTraveling && currentTravelCoroutine != null;
    public TravelRoute GetCurrentRoute() => currentRoute;

    /// <summary>
    /// Increases time speed for faster travel
    /// </summary>
    public void IncreaseTimeSpeed()
    {
        if (currentTimeSpeedIndex < timeSpeedOptions.Length - 1)
        {
            currentTimeSpeedIndex++;
            timeMultiplier = timeSpeedOptions[currentTimeSpeedIndex];
            Time.timeScale = timeMultiplier;
            Debug.Log($"⏩ Time speed increased to {timeMultiplier}x");
        }
    }

    /// <summary>
    /// Decreases time speed
    /// </summary>
    public void DecreaseTimeSpeed()
    {
        if (currentTimeSpeedIndex > 0)
        {
            currentTimeSpeedIndex--;
            timeMultiplier = timeSpeedOptions[currentTimeSpeedIndex];
            Time.timeScale = timeMultiplier;
            Debug.Log($"⏪ Time speed decreased to {timeMultiplier}x");
        }
    }

    /// <summary>
    /// Resets time speed to normal
    /// </summary>
    public void ResetTimeSpeed()
    {
        currentTimeSpeedIndex = 0;
        timeMultiplier = timeSpeedOptions[0];
        Time.timeScale = timeMultiplier;
        Debug.Log($"⏸️ Time speed reset to {timeMultiplier}x");
    }

    /// <summary>
    /// Gets current time speed multiplier
    /// </summary>
    public float GetTimeSpeed() => timeMultiplier;

    /// <summary>
    /// Methods for UI integration
    /// </summary>
    private bool IsTravelUIBlocking()
    {
        // Direct check instead of reflection since TravelUI is now available
        return travelUI != null && travelUI.IsUIBlocking();
    }

    private void ShowTravelUIIfAvailable(Vector2Int destination, List<TravelRoute> routes)
    {
        // Direct call instead of reflection since TravelUI is now available
        if (travelUI != null)
        {
            travelUI.ShowTravelUI(destination, routes);
        }
        else
        {
            Debug.LogWarning("⚠️ TravelUI not found, cannot show travel interface");
        }
    }

    public void PlanTravelWithPreferences(Vector2Int destination, bool avoidFerries, bool avoidMountainPasses, bool preferRoads)
    {
        // Store preferences and recalculate routes
        if (showDebugLogs)
        {
            Debug.Log($"🔄 Recalculating routes with preferences: AvoidFerries={avoidFerries}, AvoidMountains={avoidMountainPasses}, PreferRoads={preferRoads}");
        }

        // For now, just recalculate the same routes
        // In a full implementation, these preferences would modify the pathfinding algorithm
        PlanTravelTo(destination);
    }

    /// <summary>
    /// Forces recalculation of routes and refreshes the UI - useful for debugging or preference changes
    /// </summary>
    [ContextMenu("DEBUG: Recalculate Routes")]
    public void ForceRecalculateRoutes()
    {
        if (plannedDestination.HasValue)
        {
            Debug.Log($"🔄 TeamTravelSystem: Force recalculating routes to {plannedDestination.Value}");
            Vector2Int currentPosition = teamPlacement.GetTeamPosition();

            // Recalculate routes
            CalculateRoutes(currentPosition, plannedDestination.Value);

            // Refresh visualization
            if (availableRoutes.Count > 0)
            {
                VisualizeAllRoutes(availableRoutes);
            }

            // Refresh UI if visible
            if (travelUI != null && travelUI.IsVisible)
            {
                Debug.Log("🔄 TeamTravelSystem: Refreshing UI with recalculated routes");
                travelUI.RefreshWithNewRoutes(availableRoutes);
            }

            Debug.Log($"✅ TeamTravelSystem: Routes recalculated - {availableRoutes.Count} routes available");
        }
        else
        {
            Debug.LogWarning("⚠️ TeamTravelSystem: No planned destination to recalculate routes for");
        }
    }

    public void VisualizeSpecificRoute(TravelRoute route)
    {
        var callId = System.Guid.NewGuid().ToString("N")[..8]; // 8-character unique ID

        if (showDebugLogs)
        {
            Debug.Log($"🎯 [{callId}] VisualizeSpecificRoute called with route: {route?.routeType}, availableRoutes count: {availableRoutes?.Count ?? 0}");
        }

        if (route == null)
        {
            Debug.LogError($"❌ [{callId}] Cannot visualize null route!");
            return;
        }

        // If availableRoutes is empty, this might be because routes were cleared during UI interaction
        // In this case, we can still visualize the single route that was passed to us
        if (availableRoutes == null || availableRoutes.Count == 0)
        {
            Debug.LogWarning($"⚠️ [{callId}] availableRoutes is empty, visualizing single route {route.routeType}");

            // Temporarily add this route to the list so the visualization system can work
            if (availableRoutes == null) availableRoutes = new List<TravelRoute>();
            availableRoutes.Add(route);

            // Visualize just this route
            ClearPathVisualization();
            RenderSingleRoute(route, 0, true); // Render as selected

            if (showDebugLogs)
            {
                Debug.Log($"🎨 [{callId}] Visualized single {route.routeType} route");
            }
            return;
        }

        // Normal path when we have available routes
        // Verify the route is actually in our available routes
        bool routeExists = availableRoutes.Contains(route);
        if (!routeExists)
        {
            Debug.LogWarning($"⚠️ [{callId}] Selected route {route.routeType} is not in availableRoutes list!");
            // Try to find a matching route by type
            var matchingRoute = availableRoutes.FirstOrDefault(r => r?.routeType == route.routeType);
            if (matchingRoute != null)
            {
                Debug.Log($"🔄 [{callId}] Found matching route by type, using that instead");
                route = matchingRoute;
            }
            else
            {
                Debug.LogError($"❌ [{callId}] No matching route found, cannot visualize!");
                return;
            }
        }

        // Instead of clearing all routes, just highlight the selected one
        HighlightSpecificRoute(route);
        if (showDebugLogs)
        {
            Debug.Log($"🎨 [{callId}] Highlighted {route.routeType} route while keeping all routes visible");
        }
    }

    /// <summary>
    /// Highlights a specific route while keeping all routes visible (selected route on top)
    /// </summary>
    private void HighlightSpecificRoute(TravelRoute selectedRoute)
    {
        if (showDebugLogs)
        {
            Debug.Log($"🔍 HighlightSpecificRoute called with {selectedRoute?.routeType}, availableRoutes count: {availableRoutes.Count}");
            for (int i = 0; i < availableRoutes.Count; i++)
            {
                Debug.Log($"  Route {i}: {availableRoutes[i]?.routeType} with {availableRoutes[i]?.path?.Count ?? 0} waypoints");
            }
        }

        // Validate that we have routes to work with
        if (availableRoutes == null || availableRoutes.Count == 0)
        {
            Debug.LogError("❌ HighlightSpecificRoute: No available routes to render!");
            return;
        }

        if (selectedRoute == null)
        {
            Debug.LogError("❌ HighlightSpecificRoute: Selected route is null!");
            return;
        }

        // Clear and re-render all routes with proper transparency and layering
        ClearPathVisualization();

        // Create a copy of routes to avoid any modification issues
        var routesToRender = new List<TravelRoute>(availableRoutes);

        if (showDebugLogs)
        {
            Debug.Log($"🎨 About to render {routesToRender.Count} routes");
        }

        // First render non-selected routes with transparency
        for (int i = 0; i < routesToRender.Count; i++)
        {
            var route = routesToRender[i];
            if (route == null)
            {
                Debug.LogWarning($"⚠️ Route {i} is null, skipping");
                continue;
            }

            if (route.path == null || route.path.Count == 0)
            {
                Debug.LogWarning($"⚠️ Route {i} ({route.routeType}) has no path, skipping");
                continue;
            }

            bool isSelected = (route == selectedRoute);

            if (showDebugLogs)
            {
                Debug.Log($"🎨 Rendering route {i}: {route.routeType}, selected: {isSelected}, pathCount: {route.path.Count}");
            }

            // All routes are rendered, but with different emphasis
            RenderSingleRoute(route, i, isSelected);
        }

        if (showDebugLogs)
        {
            string routeName = selectedRoute?.routeType == RouteType.RoadPreferred ? "Fastest" :
                             selectedRoute?.routeType == RouteType.Standard ? "Shortest" : "Cheapest";
            Debug.Log($"🔝 Highlighted {routeName} route - rendered {currentPathVisualizations.Count} route visualizations");
        }
    }

    /// <summary>
    /// Renders a single route with specified layering
    /// </summary>
    private void RenderSingleRoute(TravelRoute route, int layerIndex, bool isSelected)
    {
        if (route == null || route.path.Count == 0)
        {
            if (showDebugLogs)
            {
                Debug.LogWarning($"⚠️ RenderSingleRoute: Cannot render route - route is null: {route == null}, path count: {route?.path?.Count ?? 0}");
            }
            return;
        }

        if (showDebugLogs)
        {
            Debug.Log($"🎨 RenderSingleRoute: Creating visualization for {route.routeType}, selected: {isSelected}, layerIndex: {layerIndex}");
        }

        // Create path visualization
        var pathObject = new GameObject($"TravelPath_{route.routeType}_{(isSelected ? "Selected" : "Normal")}");
        var lineRenderer = pathObject.AddComponent<LineRenderer>();

        if (showDebugLogs)
        {
            Debug.Log($"🔧 Created GameObject: {pathObject.name} with LineRenderer");
        }

        // Configure line renderer with a new material instance
        var baseMaterial = pathLineMaterial ?? CreateDefaultPathMaterial();
        var routeMaterial = new Material(baseMaterial);
        var routeColor = GetRouteColor(route);

        // Selected route gets full opacity, non-selected get good visibility
        if (isSelected)
        {
            routeColor.a = 1.0f; // Full opacity for selected
        }
        else
        {
            routeColor.a = 0.6f; // Good visibility for non-selected (was 0.8f)
        }

        routeMaterial.color = routeColor;
        lineRenderer.material = routeMaterial;

        // Selected route gets thicker line, non-selected get thinner
        float lineWidth = 1.0f;
        int sortingOrder = 50;
        switch (route.routeType)
        {
            case RouteType.RoadPreferred: // Fastest
                lineWidth = isSelected ? 2.2f : 1.4f; // More dramatic difference
                sortingOrder = isSelected ? 60 : 53;
                break;
            case RouteType.Standard: // Shortest
                lineWidth = isSelected ? 2.0f : 1.2f; // More dramatic difference
                sortingOrder = isSelected ? 59 : 52;
                break;
            case RouteType.Special: // Cheapest
                lineWidth = isSelected ? 1.8f : 1.0f; // More dramatic difference
                sortingOrder = isSelected ? 58 : 51;
                break;
        }

        lineRenderer.startWidth = lineWidth;
        lineRenderer.endWidth = lineWidth;
        lineRenderer.positionCount = route.path.Count;
        lineRenderer.useWorldSpace = true;

        // Enhanced settings with proper layering
        lineRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        lineRenderer.receiveShadows = false;
        lineRenderer.alignment = LineAlignment.View;
        lineRenderer.sortingLayerName = "Default";
        lineRenderer.sortingOrder = sortingOrder;
        lineRenderer.textureMode = LineTextureMode.Tile;

        // Selected route gets priority Y-offset (higher above map)
        float zOffset = pathLineHeight + (isSelected ? 1.0f : layerIndex * 0.2f);

        // Set path points
        for (int j = 0; j < route.path.Count; j++)
        {
            // Convert map coordinates to world coordinates properly for top-down view
            Vector3 worldPos = TileToWorldPosition(route.path[j]);

            // Add slight offset for non-selected routes to prevent exact overlap
            if (!isSelected)
            {
                float offsetAmount = layerIndex * 0.02f;
                worldPos.x += Mathf.Sin(j + layerIndex) * offsetAmount;
                worldPos.z += Mathf.Cos(j + layerIndex) * offsetAmount; // Use Z for map Y offset
            }

            worldPos.y = zOffset; // Use Y for height/depth positioning
            lineRenderer.SetPosition(j, worldPos);
        }

        currentPathVisualizations.Add(pathObject);

        if (showDebugLogs)
        {
            string routeName = route.routeType == RouteType.RoadPreferred ? "Fastest" :
                             route.routeType == RouteType.Standard ? "Shortest" : "Cheapest";
            Debug.Log($"✅ Successfully rendered {routeName} route: selected={isSelected}, width={lineWidth}, sorting={sortingOrder}, z-offset={zOffset}");
            Debug.Log($"📊 Total visualizations now: {currentPathVisualizations.Count}");
        }
    }

    public void HideTravelUI()
    {
        // Direct call instead of reflection since TravelUI is now available
        if (travelUI != null)
        {
            travelUI.HideTravelPanel();
        }
    }
}

/// <summary>
/// Represents different types of routes with GPS-style optimization goals
/// </summary>
public enum RouteType
{
    Standard,      // Shortest path (minimal distance/waypoints)
    RoadPreferred, // Fastest path (heavily prefers roads and fast terrain)
    Special        // Cheapest/Direct path (avoids special costs, takes more direct routes)
}

/// <summary>
/// Represents a complete travel route with all associated costs and information
/// </summary>
[System.Serializable]
public class TravelRoute
{
    public RouteType routeType;
    public List<Vector2Int> path;
    public float totalCost;
    public float totalDistance;
    public float estimatedTime;
    public Dictionary<string, int> specialCosts; // Special costs like ferry fees, torch usage
}

/// <summary>
/// Node used for A* pathfinding
/// </summary>
public class PathNode
{
    public Vector2Int position;
    public float gCost; // Distance from starting node
    public float hCost; // Heuristic distance to target
    public float fCost => gCost + hCost;
    public PathNode parent;
}
