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

/// <summary>
/// Manages settlement interaction on the map - detects when TeamMarker is over a settlement
/// and allows entering the town scene with proper context setup
/// </summary>
public class SettlementInteractionManager : MonoBehaviour
{
    [Header("Settlement Detection")]
    [Tooltip("The TeamMarker GameObject to track")]
    public Transform teamMarker;

    [Tooltip("How close the team marker needs to be to settlement center to interact")]
    public float interactionDistance = 2f;

    [Tooltip("Key to press to enter settlement")]
    public KeyCode enterSettlementKey = KeyCode.E;

    [Tooltip("Automatically enter settlement when TeamMarker stops moving")]
    public bool autoEnterOnStop = false;

    [Tooltip("Time to wait before auto-entering (if enabled)")]
    public float autoEnterDelay = 1f;

    [Header("UI")]
    [Tooltip("UI element to show when near settlement (optional)")]
    public GameObject interactionPrompt;

    [Header("Scene Loading")]
    [Tooltip("Name of the town scene to load")]
    public string townSceneName = "TownSceen";

    public bool enableDebugLogs = false;

    [Header("Exit Protection")]
    [Tooltip("Cooldown period after exiting a settlement before allowing re-entry")]
    public float exitCooldown = 3f;

    // Private fields
    private MapMaker2 mapMaker;
    private MapData mapData;
    private Settlement currentNearbySettlement;
    private Vector3 lastTeamMarkerPosition;
    private float timeStationary = 0f;
    private float lastExitTime = -999f; // Time when last exited a settlement
    private string lastExitedSettlement = ""; // Name of last exited settlement

    // Events
    public System.Action<Settlement> OnSettlementDetected;
    public System.Action OnSettlementLeft;
    public System.Action<Settlement> OnSettlementEntered;

    void Awake()
    {
        // Check if we're returning from a town scene
        var settlementContext = FindFirstObjectByType<SettlementContext>();
        if (settlementContext != null && !string.IsNullOrEmpty(settlementContext.settlementName))
        {
            // We just returned from a settlement - set cooldown
            lastExitTime = Time.time;
            lastExitedSettlement = settlementContext.settlementName;
            LogDebug($"COOLDOWN: Detected return from settlement: {settlementContext.settlementName} - applying {exitCooldown}s cooldown");
        }
        else
        {
            LogDebug("COOLDOWN: No settlement context found - normal startup");
        }
    }

    void Start()
    {
        InitializeComponents();
    }

    void Update()
    {
        // Retry MapData connection if it failed initially
        if (mapData == null && mapMaker != null)
        {
            mapData = mapMaker.GetMapData();
            if (mapData != null)
            {
                LogDebug($"MapData connection retry successful - Map size: {mapData.Width}x{mapData.Height}");
            }
        }

        if (teamMarker == null || mapData == null) return;

        CheckForSettlementInteraction();
        HandleInput();
        // Remove auto-enter functionality - only manual E-key entry
        // HandleAutoEnter();
    }

    /// <summary>
    /// Initialize required components and references
    /// </summary>
    private void InitializeComponents()
    {
        // Find TeamMarker if not assigned
        if (teamMarker == null)
        {
            GameObject teamMarkerObj = GameObject.Find("TeamMarker");
            if (teamMarkerObj != null)
            {
                teamMarker = teamMarkerObj.transform;
                LogDebug("Found TeamMarker automatically");
            }
            else
            {
                LogDebug("TeamMarker not found - assign manually or create GameObject named 'TeamMarker'");
                // Don't return - continue to find MapMaker2 so we can retry later
            }
        }

        // Find MapMaker2
        mapMaker = FindFirstObjectByType<MapMaker2>();
        if (mapMaker != null)
        {
            mapData = mapMaker.GetMapData();
            LogDebug($"Connected to MapMaker2 - Map size: {mapData?.Width}x{mapData?.Height}");
        }
        else
        {
            LogDebug("MapMaker2 not found - settlement detection will not work");
        }

        // Initialize UI
        if (interactionPrompt != null)
        {
            interactionPrompt.SetActive(false);
        }

        lastTeamMarkerPosition = teamMarker.position;
    }

    /// <summary>
    /// Check if TeamMarker is near any settlement
    /// </summary>
    private void CheckForSettlementInteraction()
    {
        Vector2 teamWorldPos = new Vector2(teamMarker.position.x, teamMarker.position.z);

        // Convert world position to map coordinates
        Vector2Int mapPos = WorldToMapCoordinates(teamWorldPos);

        // Find nearby settlement
        Settlement nearbySettlement = FindNearestSettlement(mapPos);

        // Handle settlement detection changes
        if (nearbySettlement != currentNearbySettlement)
        {
            if (currentNearbySettlement != null)
            {
                OnSettlementLeft?.Invoke();
                LogDebug($"Left settlement: {currentNearbySettlement.name}");
            }

            currentNearbySettlement = nearbySettlement;

            if (currentNearbySettlement != null)
            {
                OnSettlementDetected?.Invoke(currentNearbySettlement);
                LogDebug($"Near settlement: {currentNearbySettlement.name} ({currentNearbySettlement.Type})");
            }

            UpdateUI();
        }
    }

    /// <summary>
    /// Convert world coordinates to map tile coordinates
    /// </summary>
    private Vector2Int WorldToMapCoordinates(Vector2 worldPos)
    {
        // Get tile size from MapVisualizer if available
        float tileSize = 1f;
        var mapVisualizer = FindFirstObjectByType<MapVisualizer>();
        if (mapVisualizer != null && mapVisualizer.tileSize > 0)
        {
            tileSize = mapVisualizer.tileSize;
        }

        return new Vector2Int(
            Mathf.RoundToInt(worldPos.x / tileSize),
            Mathf.RoundToInt(worldPos.y / tileSize)
        );
    }

    /// <summary>
    /// Find the nearest settlement to the given map position
    /// </summary>
    private Settlement FindNearestSettlement(Vector2Int mapPos)
    {
        if (mapData == null) return null;

        // Only detect settlements when directly on the settlement tile (exact match)
        Settlement exactMatch = mapData.GetSettlementAt(mapPos);
        if (exactMatch != null)
        {
            // Check exit cooldown
            if (exactMatch.name == lastExitedSettlement && Time.time - lastExitTime < exitCooldown)
            {
                float remainingCooldown = exitCooldown - (Time.time - lastExitTime);
                LogDebug($"Settlement {exactMatch.name} on cooldown for {remainingCooldown:F1}s more");
                return null;
            }

            LogDebug($"Direct settlement match: {exactMatch.name} at {mapPos}");
            return exactMatch;
        }

        // No nearby search - only exact tile matches
        return null;
    }

    /// <summary>
    /// Handle input for settlement interaction
    /// </summary>
    private void HandleInput()
    {
        if (currentNearbySettlement != null && Input.GetKeyDown(enterSettlementKey))
        {
            EnterSettlement(currentNearbySettlement);
        }
    }

    /// <summary>
    /// Handle automatic settlement entry when stationary
    /// </summary>
    private void HandleAutoEnter()
    {
        if (!autoEnterOnStop || currentNearbySettlement == null) return;

        // Check if team marker has moved
        Vector3 currentPosition = teamMarker.position;
        float movementDistance = Vector3.Distance(currentPosition, lastTeamMarkerPosition);

        if (movementDistance < 0.1f) // Very small threshold for "stationary"
        {
            timeStationary += Time.deltaTime;

            if (timeStationary >= autoEnterDelay)
            {
                EnterSettlement(currentNearbySettlement);
                timeStationary = 0f; // Reset to prevent multiple entries
            }
        }
        else
        {
            timeStationary = 0f; // Reset timer if moving
        }

        lastTeamMarkerPosition = currentPosition;
    }

    /// <summary>
    /// Enter the specified settlement - setup context and load town scene
    /// </summary>
    public void EnterSettlement(Settlement settlement)
    {
        if (settlement == null) return;

        LogDebug($"Entering settlement: {settlement.name} ({settlement.Type})");

        // Determine if settlement has harbor (check if near water)
        bool hasHarbor = DetermineHarborPresence(settlement);

        // Set up SettlementContext
        SetupSettlementContext(settlement, hasHarbor);

        // Trigger event
        OnSettlementEntered?.Invoke(settlement);

        // Load town scene
        LoadTownScene();
    }

    /// <summary>
    /// Determine if settlement should have a harbor based on nearby terrain
    /// </summary>
    private bool DetermineHarborPresence(Settlement settlement)
    {
        if (mapData == null) return false;

        // Check nearby tiles for water
        for (int dx = -2; dx <= 2; dx++)
        {
            for (int dy = -2; dy <= 2; dy++)
            {
                int checkX = settlement.position.x + dx;
                int checkY = settlement.position.y + dy;

                var tile = mapData.GetTile(checkX, checkY);
                if (tile != null && (tile.terrainType == TerrainType.Ocean || tile.terrainType == TerrainType.Lake || tile.terrainType == TerrainType.River))
                {
                    return true;
                }
            }
        }

        return false;
    }

    /// <summary>
    /// Setup SettlementContext for scene transition
    /// </summary>
    private void SetupSettlementContext(Settlement settlement, bool hasHarbor)
    {
        // Find or create SettlementContext
        var existingContext = FindFirstObjectByType<SettlementContext>();
        SettlementContext context;

        if (existingContext != null)
        {
            context = existingContext;
        }
        else
        {
            var contextObject = new GameObject("SettlementContext");
            context = contextObject.AddComponent<SettlementContext>();
            DontDestroyOnLoad(contextObject);
        }

        // Set settlement data
        context.SetSettlement(settlement.name, settlement.Type, settlement.position, hasHarbor);

        LogDebug($"SettlementContext configured: {settlement.name} ({settlement.Type}) - Harbor: {hasHarbor}");
    }

    /// <summary>
    /// Load the town scene
    /// </summary>
    private void LoadTownScene()
    {
        LogDebug($"Loading town scene: {townSceneName}");
        SceneManager.LoadScene(townSceneName);
    }

    /// <summary>
    /// Update UI based on current settlement state
    /// </summary>
    private void UpdateUI()
    {
        if (interactionPrompt == null) return;

        if (currentNearbySettlement != null)
        {
            interactionPrompt.SetActive(true);
            // You could update text here to show settlement name and interaction key
        }
        else
        {
            interactionPrompt.SetActive(false);
        }
    }

    /// <summary>
    /// Log debug message if debug logging is enabled
    /// </summary>
    private void LogDebug(string message)
    {
        if (enableDebugLogs)
        {
            Debug.Log($"[SettlementInteraction] {message}");
        }
    }

    /// <summary>
    /// Force enter a settlement by name (for testing)
    /// </summary>
    [ContextMenu("Test Enter Current Settlement")]
    public void TestEnterCurrentSettlement()
    {
        if (currentNearbySettlement != null)
        {
            EnterSettlement(currentNearbySettlement);
        }
        else
        {
            LogDebug("No settlement nearby to enter");
        }
    }

    /// <summary>
    /// Get current nearby settlement (for external scripts)
    /// </summary>
    public Settlement GetCurrentNearbySettlement()
    {
        return currentNearbySettlement;
    }

    /// <summary>
    /// Manually set team marker reference (for external scripts)
    /// </summary>
    public void SetTeamMarker(Transform marker)
    {
        teamMarker = marker;
        if (marker != null)
        {
            lastTeamMarkerPosition = marker.position;
            LogDebug("Team marker reference updated");
        }
    }
}
