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

/// <summary>
/// Manages spottable event markers that appear as red dots within the team's perception range
/// </summary>
public class EventMarkerVisualizer : MonoBehaviour
{
    [Header("Event Marker Settings")]
    [SerializeField] private GameObject eventMarkerPrefab;
    [SerializeField] private Material eventMarkerMaterial;
    [SerializeField] private Color eventMarkerColor = Color.red;
    [SerializeField] private float markerSize = 0.8f;
    [SerializeField] private float markerHeight = 0.6f;

    [Header("Spawn Settings")]
    [SerializeField] private int maxActiveMarkers = 5;
    [SerializeField] private float minDistanceFromTeam = 2f;
    [SerializeField] private float maxDistanceFromTeam = 8f;
    [SerializeField] private float markerLifetime = 30f; // Markers disappear after 30 seconds if not approached

    [Header("Visual Effects")]
    [SerializeField] private bool enablePulsing = true;
    [SerializeField] private float pulseSpeed = 2f;
    [SerializeField] private float pulseIntensity = 0.3f;

    [Header("Debug")]
    [SerializeField] private bool showDebugInfo = false;

    // Component references
    private TeamPerceptionVisualizer perceptionVisualizer;
    private SimpleTeamPlacement teamPlacement;
    private TravelEventSystem eventSystem;
    private MapMaker2 mapMaker;

    // Active markers tracking
    private List<EventMarker> activeMarkers = new List<EventMarker>();
    private List<Vector2Int> occupiedPositions = new List<Vector2Int>();

    public static EventMarkerVisualizer Instance { get; private set; }

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

    void Start()
    {
        // Find required components
        perceptionVisualizer = FindFirstObjectByType<TeamPerceptionVisualizer>();
        teamPlacement = FindFirstObjectByType<SimpleTeamPlacement>();
        eventSystem = FindFirstObjectByType<TravelEventSystem>();
        mapMaker = FindFirstObjectByType<MapMaker2>();

        if (perceptionVisualizer == null)
        {
            Debug.LogError("EventMarkerVisualizer: TeamPerceptionVisualizer not found!");
        }

        if (teamPlacement == null)
        {
            Debug.LogError("EventMarkerVisualizer: SimpleTeamPlacement not found!");
        }
    }

    void Update()
    {
        // Clean up expired markers
        CleanupExpiredMarkers();

        // Update marker visuals (pulsing effect)
        if (enablePulsing)
        {
            UpdateMarkerPulsing();
        }
    }

    /// <summary>
    /// Attempts to spawn a spottable event marker within perception range
    /// </summary>
    /// <param name="travelEvent">The event to create a marker for</param>
    /// <returns>True if marker was successfully spawned</returns>
    public bool TrySpawnEventMarker(TravelEvent travelEvent)
    {
        if (travelEvent == null || activeMarkers.Count >= maxActiveMarkers)
        {
            return false;
        }

        // Get team position and perception range
        Vector2Int teamPosition = GetTeamPosition();
        float perceptionRange = GetTeamPerceptionRange();

        if (perceptionRange <= 0)
        {
            if (showDebugInfo)
                Debug.Log("EventMarkerVisualizer: No perception range, cannot spawn marker");
            return false;
        }

        // Find a valid position within perception range
        Vector2Int markerPosition = FindValidMarkerPosition(teamPosition, perceptionRange);
        if (markerPosition == Vector2Int.zero)
        {
            if (showDebugInfo)
                Debug.Log("EventMarkerVisualizer: Could not find valid position for event marker");
            return false;
        }

        // Create the marker
        GameObject markerObject = CreateMarkerObject(markerPosition, travelEvent);
        if (markerObject == null)
        {
            return false;
        }

        // Create event marker data
        EventMarker marker = new EventMarker
        {
            gameObject = markerObject,
            travelEvent = travelEvent,
            position = markerPosition,
            spawnTime = Time.time,
            isActive = true
        };

        activeMarkers.Add(marker);
        occupiedPositions.Add(markerPosition);

        if (showDebugInfo)
        {
            Debug.Log($"EventMarkerVisualizer: Spawned marker for '{travelEvent.eventName}' at {markerPosition}");
        }

        return true;
    }

    /// <summary>
    /// Checks if the team is close enough to trigger an event marker
    /// </summary>
    /// <param name="teamPosition">Current team position</param>
    /// <returns>The event to trigger, or null if none</returns>
    public TravelEvent CheckForMarkerTrigger(Vector2Int teamPosition)
    {
        float triggerDistance = 1.5f; // Distance to trigger event

        foreach (var marker in activeMarkers.ToList())
        {
            if (!marker.isActive) continue;

            float distance = Vector2Int.Distance(teamPosition, marker.position);
            if (distance <= triggerDistance)
            {
                // Remove the marker and return the event
                RemoveMarker(marker);

                if (showDebugInfo)
                {
                    Debug.Log($"EventMarkerVisualizer: Team triggered event '{marker.travelEvent.eventName}' at {marker.position}");
                }

                return marker.travelEvent;
            }
        }

        return null;
    }

    /// <summary>
    /// Removes all active event markers
    /// </summary>
    public void ClearAllMarkers()
    {
        foreach (var marker in activeMarkers.ToList())
        {
            RemoveMarker(marker);
        }
    }

    private Vector2Int GetTeamPosition()
    {
        if (teamPlacement != null)
        {
            return teamPlacement.GetCurrentTeamPosition();
        }
        return Vector2Int.zero;
    }

    private float GetTeamPerceptionRange()
    {
        if (perceptionVisualizer != null)
        {
            // Access the perception range from the visualizer
            // We need to get the team's highest perception and apply the multiplier
            return GetHighestTeamPerception() * 1.0f; // Use same multiplier as perception visualizer
        }
        return 0f;
    }

    private int GetHighestTeamPerception()
    {
        // This mirrors the logic from TeamPerceptionVisualizer
        int maxPerception = 0;
        List<TeamCharacter> teamMembers = GetCurrentTeamMembers();

        if (teamMembers == null || teamMembers.Count == 0)
            return 0;

        foreach (TeamCharacter character in teamMembers)
        {
            if (character != null)
            {
                int characterPerception = character.FinalPerception;
                if (characterPerception > maxPerception)
                {
                    maxPerception = characterPerception;
                }
            }
        }

        return maxPerception;
    }

    private List<TeamCharacter> GetCurrentTeamMembers()
    {
        // Use the same logic as TeamPerceptionVisualizer
        var teamSelectScript = FindFirstObjectByType<MainTeamSelectScript>();
        var gameStateManager = FindFirstObjectByType<GameStateManager>();

        // Try to get team from MainTeamSelectScript first
        if (teamSelectScript != null)
        {
            var configuredCharacters = teamSelectScript.GetConfiguredCharacters();
            if (configuredCharacters != null && configuredCharacters.Count > 0)
            {
                return configuredCharacters;
            }
        }

        // Fall back to GameStateManager
        if (gameStateManager != null && gameStateManager.savedTeam != null)
        {
            var savedTeamList = new List<TeamCharacter>();
            foreach (var character in gameStateManager.savedTeam)
            {
                if (character != null)
                    savedTeamList.Add(character);
            }

            if (savedTeamList.Count > 0)
            {
                return savedTeamList;
            }
        }

        // Final fallback: Load from PlayerPrefs
        var playerPrefTeam = new List<TeamCharacter>();
        for (int i = 0; i < 4; i++)
        {
            string prefix = $"Character{i}_";
            if (PlayerPrefs.HasKey(prefix + "Exists") && PlayerPrefs.GetInt(prefix + "Exists") == 1)
            {
                var character = new TeamCharacter();
                character.name = PlayerPrefs.GetString(prefix + "Name", "");
                character.isMale = PlayerPrefs.GetInt(prefix + "IsMale", 1) == 1;
                character.strength = PlayerPrefs.GetInt(prefix + "Strength", 10);
                character.dexterity = PlayerPrefs.GetInt(prefix + "Dexterity", 10);
                character.constitution = PlayerPrefs.GetInt(prefix + "Constitution", 10);
                character.wisdom = PlayerPrefs.GetInt(prefix + "Wisdom", 10);
                character.perception = PlayerPrefs.GetInt(prefix + "Perception", 10);
                character.gold = PlayerPrefs.GetInt(prefix + "Gold", 25);

                playerPrefTeam.Add(character);
            }
        }

        return playerPrefTeam.Count > 0 ? playerPrefTeam : null;
    }

    private Vector2Int FindValidMarkerPosition(Vector2Int teamPosition, float perceptionRange)
    {
        int maxAttempts = 20;

        for (int i = 0; i < maxAttempts; i++)
        {
            // Generate random position within perception range
            float angle = Random.Range(0f, 360f) * Mathf.Deg2Rad;
            float distance = Random.Range(minDistanceFromTeam, Mathf.Min(maxDistanceFromTeam, perceptionRange));

            Vector2Int candidatePosition = new Vector2Int(
                teamPosition.x + Mathf.RoundToInt(Mathf.Cos(angle) * distance),
                teamPosition.y + Mathf.RoundToInt(Mathf.Sin(angle) * distance)
            );

            // Check if position is valid
            if (IsValidMarkerPosition(candidatePosition))
            {
                return candidatePosition;
            }
        }

        return Vector2Int.zero; // Failed to find valid position
    }

    private bool IsValidMarkerPosition(Vector2Int position)
    {
        // Check if position is already occupied
        if (occupiedPositions.Contains(position))
        {
            return false;
        }

        // Check if position is valid on the map
        if (mapMaker != null && mapMaker.GetMapData() != null)
        {
            return mapMaker.GetMapData().IsValidPosition(position.x, position.y);
        }

        return true; // Default to valid if no map check available
    }

    private GameObject CreateMarkerObject(Vector2Int position, TravelEvent travelEvent)
    {
        GameObject markerObject;

        if (eventMarkerPrefab != null)
        {
            markerObject = Instantiate(eventMarkerPrefab);
        }
        else
        {
            // Create simple sphere marker
            markerObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            markerObject.transform.localScale = Vector3.one * markerSize;

            // Remove collider to avoid interference
            var collider = markerObject.GetComponent<Collider>();
            if (collider != null)
            {
                DestroyImmediate(collider);
            }
        }

        // Position the marker
        Vector3 worldPosition = GetWorldPosition(position);
        markerObject.transform.position = worldPosition;

        // Apply material and color
        ApplyMarkerMaterial(markerObject);

        // Add tooltip component for hover information using reflection (compilation-safe)
        var tooltipType = System.Type.GetType("EventMarkerTooltip");
        if (tooltipType != null)
        {
            var tooltip = markerObject.AddComponent(tooltipType) as MonoBehaviour;
            if (tooltip != null)
            {
                // Use reflection to call Initialize method
                var initMethod = tooltipType.GetMethod("Initialize");
                initMethod?.Invoke(tooltip, new object[] { travelEvent });
            }
        }
        else if (showDebugInfo)
        {
            Debug.Log("EventMarkerTooltip component not found - tooltips will not be available");
        }

        // Set name and tag
        markerObject.name = "EventMarker";
        // Use default "Untagged" tag to avoid tag definition errors
        markerObject.tag = "Untagged";

        return markerObject;
    }

    private Vector3 GetWorldPosition(Vector2Int mapPosition)
    {
        // Convert map coordinates to world position
        float tileSize = 1f;
        if (mapMaker?.mapVisualizer != null)
        {
            tileSize = mapMaker.mapVisualizer.tileSize;
        }

        return new Vector3(
            mapPosition.x * tileSize,
            markerHeight,
            mapPosition.y * tileSize
        );
    }

    private void ApplyMarkerMaterial(GameObject markerObject)
    {
        Renderer renderer = markerObject.GetComponent<Renderer>();
        if (renderer == null) return;

        if (eventMarkerMaterial != null)
        {
            renderer.material = eventMarkerMaterial;
        }
        else
        {
            // Create a simple red material
            Material material = new Material(Shader.Find("Universal Render Pipeline/Lit"));
            if (material.shader == null)
            {
                material = new Material(Shader.Find("Standard"));
            }

            material.color = eventMarkerColor;

            // Add emission for visibility
            if (material.HasProperty("_EmissionColor"))
            {
                material.EnableKeyword("_EMISSION");
                material.SetColor("_EmissionColor", eventMarkerColor * 0.5f);
            }

            renderer.material = material;
        }
    }

    private void CleanupExpiredMarkers()
    {
        var markersToRemove = activeMarkers.Where(m =>
            !m.isActive ||
            m.gameObject == null ||
            (Time.time - m.spawnTime) > markerLifetime
        ).ToList();

        foreach (var marker in markersToRemove)
        {
            RemoveMarker(marker);
        }
    }

    private void UpdateMarkerPulsing()
    {
        float pulseValue = (Mathf.Sin(Time.time * pulseSpeed) + 1f) * 0.5f; // 0 to 1
        float scale = 1f + (pulseValue * pulseIntensity);

        foreach (var marker in activeMarkers)
        {
            if (marker.isActive && marker.gameObject != null)
            {
                marker.gameObject.transform.localScale = Vector3.one * (markerSize * scale);
            }
        }
    }

    private void RemoveMarker(EventMarker marker)
    {
        if (marker.gameObject != null)
        {
            DestroyImmediate(marker.gameObject);
        }

        activeMarkers.Remove(marker);
        occupiedPositions.Remove(marker.position);
        marker.isActive = false;
    }

    /// <summary>
    /// Gets the number of currently active event markers
    /// </summary>
    public int GetActiveMarkerCount()
    {
        return activeMarkers.Count(m => m.isActive);
    }

    /// <summary>
    /// Debug method to show all active markers
    /// </summary>
    [ContextMenu("Show Active Markers")]
    public void ShowActiveMarkers()
    {
        Debug.Log($"=== Active Event Markers ({activeMarkers.Count}) ===");
        foreach (var marker in activeMarkers)
        {
            if (marker.isActive)
            {
                float age = Time.time - marker.spawnTime;
                Debug.Log($"- {marker.travelEvent.eventName} at {marker.position} (age: {age:F1}s)");
            }
        }
    }
}

/// <summary>
/// Data structure for tracking active event markers
/// </summary>
[System.Serializable]
public class EventMarker
{
    public GameObject gameObject;
    public TravelEvent travelEvent;
    public Vector2Int position;
    public float spawnTime;
    public bool isActive;
}
