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

/// <summary>
/// Main travel event system that manages when and where events occur during travel
/// Integrates with the existing TeamTravelSystem
/// </summary>
public class TravelEventSystem : MonoBehaviour
{
    [Header("Event System Settings")]
    public bool enableEvents = true;
    [Range(0f, 1f)]
    public float baseEventChance = 0.1f; // 10% chance per tile check (reduced from 15%)
    [Range(1, 10)]
    public int tilesPerEventCheck = 4; // Check for events every 4 tiles (increased from 3)

    [Header("Event Collections")]
    public List<TravelEvent> availableEvents = new List<TravelEvent>();

    [Header("Debug")]
    public bool showDebugLogs = true;
    public bool forceNextEvent = false; // For testing

    // Event tracking
    private TravelEventHistory globalEventHistory;
    private int tilesTraveledSinceLastCheck = 0;
    private TravelEventContext currentContext;
    private Vector2Int lastTeamPosition = Vector2Int.zero;
    private bool hasInitializedPosition = false;

    // Component references
    private TeamTravelSystem travelSystem;
    private MapMaker2 mapMaker;
    private SimpleTeamPlacement teamPlacement;
    private TravelEventUI eventUI;
    private MonoBehaviour markerVisualizer; // Use MonoBehaviour to avoid compilation issues
    // Enhanced system will be linked after compilation
    private object enhancedEventSystem;

    void Start()
    {
        // Find required components
        travelSystem = FindFirstObjectByType<TeamTravelSystem>();
        mapMaker = FindFirstObjectByType<MapMaker2>();
        teamPlacement = FindFirstObjectByType<SimpleTeamPlacement>();
        eventUI = FindFirstObjectByType<TravelEventUI>();

        // Find EventMarkerVisualizer using reflection to avoid compilation order issues
        var markerVisualizerComponents = FindObjectsByType<MonoBehaviour>(FindObjectsSortMode.None);
        markerVisualizer = System.Array.Find(markerVisualizerComponents,
            comp => comp.GetType().Name == "EventMarkerVisualizer");

        // Enhanced system will be found after compilation
        // enhancedEventSystem = FindFirstObjectByType<EnhancedTravelEventSystem>();

        globalEventHistory = new TravelEventHistory();

        if (showDebugLogs)
        {
            Debug.Log($"🎲 Travel Event System initialized with {availableEvents.Count} events");
            if (eventUI == null)
                Debug.LogWarning("⚠️ TravelEventUI not found. Event messages will only appear in console.");
            LogEventDistribution();
        }

        // Load default events if none are assigned
        if (availableEvents.Count == 0)
        {
            LoadDefaultEvents();
        }
    }

    void Update()
    {
        if (!enableEvents || travelSystem == null) return;

        // Track actual tile movement instead of frame-based checks
        Vector2Int currentTeamPosition = GetCurrentTeamPosition();

        if (!hasInitializedPosition)
        {
            lastTeamPosition = currentTeamPosition;
            hasInitializedPosition = true;
            return;
        }

        // Only check for events when the team actually moves to a new tile
        if (currentTeamPosition != lastTeamPosition)
        {
            tilesTraveledSinceLastCheck++;

            if (showDebugLogs)
            {
                Debug.Log($"🚶 Team moved from {lastTeamPosition} to {currentTeamPosition} (tiles since last check: {tilesTraveledSinceLastCheck})");
            }

            // Check for event marker triggers first
            CheckForEventMarkerTriggers(currentTeamPosition);

            lastTeamPosition = currentTeamPosition;

            // Check for events every N tiles traveled
            if (tilesTraveledSinceLastCheck >= tilesPerEventCheck)
            {
                if (showDebugLogs)
                {
                    Debug.Log($"🎲 Checking for travel event after {tilesTraveledSinceLastCheck} tiles traveled");
                }
                CheckForTravelEvent();
                tilesTraveledSinceLastCheck = 0;
            }
        }
    }

    /// <summary>
    /// Main method to check if a travel event should occur
    /// </summary>
    public void CheckForTravelEvent()
    {
        if (!enableEvents) return;

        // Get current travel context
        currentContext = CreateCurrentContext();
        if (currentContext == null) return;

        // Calculate if an event should occur
        float eventRoll = Random.value;
        float eventThreshold = CalculateEventThreshold(currentContext);

        // Force event for testing
        if (forceNextEvent)
        {
            forceNextEvent = false;
            eventRoll = 0f; // Guarantee event
            eventThreshold = 1f;
        }

        if (eventRoll <= eventThreshold)
        {
            TriggerRandomEvent(currentContext);
        }
    }

    /// <summary>
    /// Force a specific event to occur (for testing or story purposes)
    /// </summary>
    public void TriggerSpecificEvent(TravelEvent eventToTrigger)
    {
        if (eventToTrigger == null) return;

        currentContext = CreateCurrentContext();
        if (currentContext == null) return;

        ExecuteEvent(eventToTrigger, currentContext);
    }

    /// <summary>
    /// Check if team has triggered any event markers
    /// </summary>
    private void CheckForEventMarkerTriggers(Vector2Int teamPosition)
    {
        if (markerVisualizer == null) return;

        // Use reflection to call CheckForMarkerTrigger method
        var method = markerVisualizer.GetType().GetMethod("CheckForMarkerTrigger");
        if (method != null)
        {
            var triggeredEvent = method.Invoke(markerVisualizer, new object[] { teamPosition }) as TravelEvent;
            if (triggeredEvent != null)
            {
                // Create context and execute the triggered event
                currentContext = CreateCurrentContext();
                if (currentContext != null)
                {
                    ExecuteEvent(triggeredEvent, currentContext);
                }
            }
        }
    }

    /// <summary>
    /// Trigger a random event based on current context
    /// </summary>
    private void TriggerRandomEvent(TravelEventContext context)
    {
        var possibleEvents = GetPossibleEvents(context);
        if (possibleEvents.Count == 0)
        {
            if (showDebugLogs)
                Debug.Log("🎲 No valid events found for current context");
            return;
        }

        // Separate events by trigger type
        var automaticEvents = possibleEvents.Where(e => e.triggerType == EventTriggerType.Automatic).ToList();
        var spottableEvents = possibleEvents.Where(e => e.triggerType == EventTriggerType.Spottable).ToList();

        // Try to trigger automatic event first
        if (automaticEvents.Count > 0)
        {
            TravelEvent selectedEvent = SelectWeightedEvent(automaticEvents, context);
            if (selectedEvent != null)
            {
                ExecuteEvent(selectedEvent, context);
                return;
            }
        }

        // Try to spawn spottable event markers
        if (spottableEvents.Count > 0 && markerVisualizer != null)
        {
            TravelEvent selectedSpottableEvent = SelectWeightedEvent(spottableEvents, context);
            if (selectedSpottableEvent != null)
            {
                // Use reflection to call TrySpawnEventMarker method
                var spawnMethod = markerVisualizer.GetType().GetMethod("TrySpawnEventMarker");
                if (spawnMethod != null)
                {
                    var markerSpawned = (bool)spawnMethod.Invoke(markerVisualizer, new object[] { selectedSpottableEvent });
                    if (markerSpawned && showDebugLogs)
                    {
                        Debug.Log($"🔴 Spawned spottable event marker: {selectedSpottableEvent.eventName}");
                    }
                }
            }
        }
    }

    /// <summary>
    /// Execute a travel event and handle its results
    /// </summary>
    private void ExecuteEvent(TravelEvent travelEvent, TravelEventContext context)
    {
        if (showDebugLogs)
        {
            Debug.Log($"🎭 Executing event: {travelEvent.eventName} at {context.currentPosition}");
        }

        // Execute the event
        EventResult result = travelEvent.ExecuteEvent(context);

        if (!result.eventOccurred)
        {
            if (showDebugLogs)
                Debug.Log($"🎭 Event {travelEvent.eventName} chose not to occur");
            return;
        }

        // Record the event
        globalEventHistory.RecordEvent(travelEvent, context);

        // Display event message (unless suppressed by popup system)
        if (!result.suppressMessage)
        {
            if (eventUI != null)
            {
                eventUI.ShowEventResult(result);
            }
            else
            {
                ShowEventMessage(result.resultMessage);
            }
        }

        // Handle the event result
        HandleEventResult(result, context);
    }

    /// <summary>
    /// Handle the results of a travel event
    /// </summary>
    private void HandleEventResult(EventResult result, TravelEventContext context)
    {
        // Apply resource changes
        ApplyResourceChanges(result);

        // Handle special event types
        if (result.shouldStopTravel)
        {
            if (travelSystem != null)
            {
                // Stop current travel using the existing cancellation system
                travelSystem.CancelJourney();
                Debug.Log("🛑 Travel stopped due to event");
            }
        }

        if (result.startBattle)
        {
            HandleBattleEvent(result.battleData, context);
        }

        if (result.openTrading)
        {
            HandleTradingEvent(result.tradingData, context);
        }
    }

    /// <summary>
    /// Create travel event context from current game state
    /// </summary>
    private TravelEventContext CreateCurrentContext()
    {
        if (teamPlacement == null || mapMaker == null || travelSystem == null)
            return null;

        Vector2Int currentPos = teamPlacement.GetCurrentTeamPosition();
        var mapData = mapMaker.GetMapData();
        var currentTile = mapData.GetTile(currentPos.x, currentPos.y);
        var currentRoute = travelSystem.GetCurrentRoute();

        var context = new TravelEventContext(currentPos, currentTile, currentRoute)
        {
            dayOfJourney = 1, // This could be tracked elsewhere
            timeOfDay = 12f, // This could be from a day/night system
            teamGold = 100, // This should come from actual team resources
            teamFood = 50,
            eventHistory = globalEventHistory
        };

        // Set travel context
        if (currentRoute != null)
        {
            context.destination = travelSystem.GetPlannedDestination() ?? currentPos;
            context.isOnMainRoad = currentTile.featureType == FeatureType.Road;
        }

        return context;
    }

    /// <summary>
    /// Calculate the threshold for events to occur based on context
    /// </summary>
    private float CalculateEventThreshold(TravelEventContext context)
    {
        float threshold = baseEventChance;

        // Modify based on terrain (some areas are more eventful)
        switch (context.currentTile.terrainType)
        {
            case TerrainType.Forest:
                threshold *= 1.3f; // More events in forests
                break;
            case TerrainType.Mountain:
                threshold *= 1.4f; // Even more in mountains
                break;
            case TerrainType.Plains:
                threshold *= 0.8f; // Fewer in plains
                break;
        }

        // Modify based on features
        switch (context.currentTile.featureType)
        {
            case FeatureType.Road:
                threshold *= 0.7f; // Fewer events on roads (safer travel)
                break;
            case FeatureType.Town:
            case FeatureType.Village:
                threshold *= 0.5f; // Much fewer in settlements
                break;
        }

        return Mathf.Clamp01(threshold);
    }

    /// <summary>
    /// Get all events that can occur in the current context
    /// </summary>
    private List<TravelEvent> GetPossibleEvents(TravelEventContext context)
    {
        return availableEvents.Where(e => e != null && e.CanOccur(context)).ToList();
    }

    /// <summary>
    /// Select an event based on weighted probabilities
    /// </summary>
    private TravelEvent SelectWeightedEvent(List<TravelEvent> events, TravelEventContext context)
    {
        if (events.Count == 0) return null;
        if (events.Count == 1) return events[0];

        // Calculate weights
        var weights = events.Select(e => e.GetEventChance(context.currentTile)).ToList();
        float totalWeight = weights.Sum();

        if (totalWeight <= 0) return null;

        // Select based on weight
        float randomValue = Random.value * totalWeight;
        float currentWeight = 0f;

        for (int i = 0; i < events.Count; i++)
        {
            currentWeight += weights[i];
            if (randomValue <= currentWeight)
            {
                return events[i];
            }
        }

        return events.Last(); // Fallback
    }

    /// <summary>
    /// Apply resource changes from event results
    /// </summary>
    private void ApplyResourceChanges(EventResult result)
    {
        if (result.goldChange != 0)
        {
            // Apply gold change to team resources
            // This would integrate with your resource system
            Debug.Log($"💰 Gold changed by {result.goldChange}");
        }

        if (result.healthChange != 0)
        {
            // Apply health change to team
            // This would integrate with your character health system
            Debug.Log($"❤️ Health changed by {result.healthChange}");
        }

        if (result.foodChange != 0)
        {
            // Apply food change
            Debug.Log($"🍖 Food changed by {result.foodChange}");
        }
    }

    /// <summary>
    /// Handle battle events by setting up battle data
    /// </summary>
    private void HandleBattleEvent(BattleEventData battleData, TravelEventContext context)
    {
        if (battleData == null) return;

        // Try to use enhanced event system for player choice popup
        var enhancedSystem = FindFirstObjectByType(System.Type.GetType("EnhancedTravelEventSystem"));
        if (enhancedSystem != null)
        {
            Debug.Log("🎭 Using Enhanced Travel Event System for combat popup");

            // Use reflection to call the enhanced handler
            var method = enhancedSystem.GetType().GetMethod("HandleEnhancedBattleEvent");
            if (method != null)
            {
                string eventDescription = $"Your party encounters {battleData.enemyCount} {battleData.enemyType}!";
                method.Invoke(enhancedSystem, new object[] { battleData, context, eventDescription });
                return;
            }
        }

        // Fallback to original battle handling
        Debug.Log($"⚔️ Setting up battle: {battleData.enemyCount} {battleData.enemyType}(s)");

        // Enhanced battle setup using EnemyCharacterData if available
        if (battleData.enemyCharacterData != null)
        {
            Debug.Log($"🎯 Using enemy data: {battleData.enemyCharacterData.enemyName}");
            Debug.Log($"📊 Enemy stats: HP={battleData.enemyCharacterData.maxHealth}, " +
                     $"AC={battleData.enemyCharacterData.armorClass}, " +
                     $"Threat={battleData.enemyCharacterData.threatLevel}");

            // TODO: Enhanced battle setup with actual enemy data
            /*
            BattleSetupData.enemySelections.Clear();
            for (int i = 0; i < battleData.enemyCount; i++)
            {
                var enemyData = battleData.enemyCharacterData;
                BattleSetupData.enemySelections.Add(new CharacterSelection
                {
                    characterName = $"{enemyData.enemyName}_{i+1}",
                    weaponType = enemyData.preferredWeapon != null ? enemyData.preferredWeapon.weaponType.ToString() : "Sword",
                    // Could also include:
                    // health = enemyData.maxHealth,
                    // armorClass = enemyData.armorClass,
                    // threatLevel = enemyData.threatLevel
                });
            }
            */
        }
        else
        {
            // Fallback to string-based system
            Debug.Log("⚠️ No EnemyCharacterData found, using legacy string-based setup");
            /*
            BattleSetupData.enemySelections.Clear();
            for (int i = 0; i < battleData.enemyCount; i++)
            {
                BattleSetupData.enemySelections.Add(new CharacterSelection
                {
                    characterName = $"{battleData.enemyType}_{i+1}",
                    weaponType = "Sword" // Could be randomized
                });
            }
            */
        }
    }

    /// <summary>
    /// Handle trading events by opening shop interface
    /// </summary>
    private void HandleTradingEvent(TradingEventData tradingData, TravelEventContext context)
    {
        if (tradingData == null) return;

        Debug.Log($"🛒 Opening trading with {tradingData.merchantType}");

        // This would open your shop system
        // You could modify shop inventory based on merchantType and hasRareItems
    }

    /// <summary>
    /// Display event message to player
    /// </summary>
    private void ShowEventMessage(string message)
    {
        if (string.IsNullOrEmpty(message)) return;

        Debug.Log($"📜 EVENT: {message}");

        // Use UI system if available
        if (eventUI != null)
        {
            eventUI.ShowEventMessage(message);
        }
    }

    /// <summary>
    /// Load default events if none are assigned in inspector
    /// </summary>
    private void LoadDefaultEvents()
    {
        // Load default events from Resources folder
        TravelEvent[] defaultEvents = Resources.LoadAll<TravelEvent>("TravelEvents");
        availableEvents.AddRange(defaultEvents);

        if (showDebugLogs)
        {
            Debug.Log($"🔄 Loaded {defaultEvents.Length} default events from Resources");
        }
    }

    /// <summary>
    /// Debug method to show event distribution
    /// </summary>
    private void LogEventDistribution()
    {
        if (!showDebugLogs) return;

        var eventsByType = availableEvents.GroupBy(e => e.eventType);
        foreach (var group in eventsByType)
        {
            Debug.Log($"📊 {group.Key}: {group.Count()} events");
        }
    }

    /// <summary>
    /// Public method to trigger event check manually (for testing)
    /// </summary>
    [ContextMenu("Trigger Event Check")]
    public void TriggerEventCheck()
    {
        forceNextEvent = true;
        CheckForTravelEvent();
    }

    /// <summary>
    /// Reset event history (useful for testing)
    /// </summary>
    [ContextMenu("Reset Event History")]
    public void ResetEventHistory()
    {
        globalEventHistory = new TravelEventHistory();
        tilesTraveledSinceLastCheck = 0;
        Debug.Log("🔄 Event history reset");
    }

    /// <summary>
    /// Get the current team position in tile coordinates
    /// </summary>
    private Vector2Int GetCurrentTeamPosition()
    {
        if (teamPlacement == null)
            return Vector2Int.zero;

        var teamMarker = teamPlacement.GetTeamMarker();
        if (teamMarker == null)
            return Vector2Int.zero;

        // Convert world position to tile position
        Vector3 worldPos = teamMarker.transform.position;
        return new Vector2Int(
            Mathf.RoundToInt(worldPos.x),
            Mathf.RoundToInt(worldPos.z)
        );
    }
}
