using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System.Collections.Generic;

/// <summary>
/// TeamHUDPanel — FRAG-style circular portrait HUD showing team health and character switching.
///
/// SETUP (Inspector):
///   1. Create your HUD layout manually — place circular Image slots wherever you want.
///   2. Assign them into the lists below:
///        - characterPortraits[] — Image where the character icon/portrait sprite will go
///        - healthDialImages[]   — Image used as a radial-fill health ring around each portrait
///        - dialBackgrounds[]    — (optional) background ring images behind the health dials
///        - nameLabels[]         — (optional) TMP text for character names
///   3. The script fills sprites and updates health dials every frame.
///   4. Click/tap a portrait to switch control to that character.
///
/// Uses CanvasGroup to hide initially — stays alive for Initialize() call.
/// </summary>
public class TeamHUDPanel : MonoBehaviour
{
    [Header("Character Portraits (assign in order: index 0 = team slot 0, etc.)")]
    [Tooltip("Image components where character icon sprites will be placed")]
    [SerializeField] private List<Image> characterPortraits = new List<Image>();

    [Header("Health Dial Rings (same index order as portraits)")]
    [Tooltip("Image components used as radial-fill health rings — set to Filled/Radial360 at runtime")]
    [SerializeField] private List<Image> healthDialImages = new List<Image>();

    [Header("Dial Backgrounds (optional, same index order)")]
    [Tooltip("Background ring images behind each health dial")]
    [SerializeField] private List<Image> dialBackgrounds = new List<Image>();

    [Header("Name Labels (optional, same index order)")]
    [SerializeField] private List<TextMeshProUGUI> nameLabels = new List<TextMeshProUGUI>();

    [Header("Dead Overlay (optional, same index order)")]
    [Tooltip("GameObjects to show when a character is dead (e.g. a dark overlay with X)")]
    [SerializeField] private List<GameObject> deadOverlays = new List<GameObject>();

    [Header("Highlight Border (optional, same index order)")]
    [Tooltip("Image used as a highlight border — only visible on the active character")]
    [SerializeField] private List<Image> highlightBorders = new List<Image>();

    [Header("Dial Sprite")]
    [Tooltip("Sprite for the health dial ring. If empty, tries to copy from ImportUIPanel's ProgressDial.")]
    [SerializeField] private Sprite dialSprite;

    [Header("Audio")]
    [SerializeField] private AudioClip switchSFX;
    [SerializeField] private AudioClip buttonHoverSFX;
    [SerializeField] private float sfxVolume = 1f;

    [Header("Colors")]
    [SerializeField] private Color healthFullColor    = new Color(0.30f, 0.87f, 0.30f, 1f);
    [SerializeField] private Color healthLowColor     = new Color(0.96f, 0.26f, 0.21f, 1f);
    [SerializeField] private Color highlightColor     = new Color(1f, 0.84f, 0f, 1f);
    [SerializeField] private Color defaultBorderColor = new Color(0.3f, 0.3f, 0.3f, 0.6f);

    // runtime
    private List<GameObject> _characters = new List<GameObject>();
    private List<HealthNew>  _healthComps = new List<HealthNew>();
    private int _currentHighlight = -1;
    private CanvasGroup _canvasGroup;
    private AudioSource _audio;

    private static TeamHUDPanel _instance;
    public static TeamHUDPanel Instance => _instance;

    private void Awake()
    {
        _instance = this;

        _canvasGroup = GetComponent<CanvasGroup>();
        if (_canvasGroup == null) _canvasGroup = gameObject.AddComponent<CanvasGroup>();

        _audio = GetComponent<AudioSource>();
        if (_audio == null) _audio = gameObject.AddComponent<AudioSource>();
        _audio.playOnAwake = false;
        _audio.spatialBlend = 0f;

        // Hide via CanvasGroup until Initialize is called
        HideImmediate();

        // Try to find dial sprite from ImportUIPanel if not assigned
        if (dialSprite == null)
        {
            var importPanel = GameObject.Find("ImportUIPanel");
            if (importPanel != null)
            {
                var dial = importPanel.transform.Find("ProgressDial");
                if (dial != null)
                {
                    var img = dial.GetComponent<Image>();
                    if (img != null) dialSprite = img.sprite;
                }
            }
        }
    }

    private void OnEnable()
    {
        GameEvents.OnCharacterSwitched += OnCharacterSwitched;
    }

    private void OnDisable()
    {
        GameEvents.OnCharacterSwitched -= OnCharacterSwitched;
    }

    // ─── Public API ──────────────────────────────────────────

    /// <summary>
    /// Initialize the HUD with the player team characters.
    /// Call after characters are spawned (from CashSystemManager.SpawnTeams).
    /// </summary>
    public void Initialize(List<GameObject> playerTeamCharacters, int currentControlledIndex)
    {
        DevLog.Log($"[TeamHUDPanel] Initialize with {playerTeamCharacters?.Count ?? 0} characters, active={currentControlledIndex}");

        _characters.Clear();
        _healthComps.Clear();

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

        int count = Mathf.Min(playerTeamCharacters.Count, characterPortraits.Count);

        for (int i = 0; i < count; i++)
        {
            GameObject character = playerTeamCharacters[i];
            _characters.Add(character);
            _healthComps.Add(character != null ? character.GetComponent<HealthNew>() : null);

            // Set portrait sprite
            if (i < characterPortraits.Count && characterPortraits[i] != null && character != null)
            {
                Sprite icon = GetCharacterIcon(character);
                if (icon != null)
                {
                    characterPortraits[i].sprite = icon;
                    characterPortraits[i].color  = Color.white;
                    characterPortraits[i].preserveAspect = true;
                }

                // Add click handler
                int capturedIndex = i;
                Button btn = characterPortraits[i].GetComponent<Button>();
                if (btn == null) btn = characterPortraits[i].gameObject.AddComponent<Button>();
                btn.transition = Selectable.Transition.None;
                btn.onClick.RemoveAllListeners();
                btn.onClick.AddListener(() => OnSlotClicked(capturedIndex));
            }

            // Configure health dial as radial fill
            if (i < healthDialImages.Count && healthDialImages[i] != null)
            {
                Image dial = healthDialImages[i];
                if (dialSprite != null) dial.sprite = dialSprite;
                dial.type = Image.Type.Filled;
                dial.fillMethod = Image.FillMethod.Radial360;
                dial.fillOrigin = (int)Image.Origin360.Top;
                dial.fillClockwise = true;
                dial.fillAmount = 1f;
                dial.color = healthFullColor;
            }

            // Set name label
            if (i < nameLabels.Count && nameLabels[i] != null && character != null)
            {
                nameLabels[i].text = GetCharacterName(character);
            }

            // Hide dead overlay
            if (i < deadOverlays.Count && deadOverlays[i] != null)
            {
                deadOverlays[i].SetActive(false);
            }

            // Default border
            if (i < highlightBorders.Count && highlightBorders[i] != null)
            {
                highlightBorders[i].color = defaultBorderColor;
            }
        }

        // Hide any extra slots beyond team size
        for (int i = count; i < characterPortraits.Count; i++)
        {
            if (characterPortraits[i] != null) characterPortraits[i].gameObject.SetActive(false);
            if (i < healthDialImages.Count && healthDialImages[i] != null) healthDialImages[i].gameObject.SetActive(false);
            if (i < dialBackgrounds.Count && dialBackgrounds[i] != null) dialBackgrounds[i].gameObject.SetActive(false);
            if (i < nameLabels.Count && nameLabels[i] != null) nameLabels[i].gameObject.SetActive(false);
            if (i < deadOverlays.Count && deadOverlays[i] != null) deadOverlays[i].SetActive(false);
            if (i < highlightBorders.Count && highlightBorders[i] != null) highlightBorders[i].gameObject.SetActive(false);
        }

        SetHighlight(currentControlledIndex);

        // Show panel
        _canvasGroup.alpha = 1f;
        _canvasGroup.blocksRaycasts = true;
        _canvasGroup.interactable = true;
    }

    /// <summary>Update health dials + keyboard shortcuts. Health polling throttled to ~10Hz.</summary>
    private void Update()
    {
        // Keyboard shortcuts: 1, 2, 3 to switch characters (always responsive)
        if (_characters.Count > 0 && _canvasGroup.alpha > 0f)
        {
            if (Input.GetKeyDown(KeyCode.Alpha1) && _characters.Count > 0) OnSlotClicked(0);
            if (Input.GetKeyDown(KeyCode.Alpha2) && _characters.Count > 1) OnSlotClicked(1);
            if (Input.GetKeyDown(KeyCode.Alpha3) && _characters.Count > 2) OnSlotClicked(2);
        }

        // Throttle health polling to every 6th frame (~10Hz at 60fps)
        // Health bars update smoothly enough at 10Hz — indistinguishable from 60Hz
        if (Time.frameCount % 6 != 0) return;

        for (int i = 0; i < _healthComps.Count; i++)
        {
            HealthNew h = _healthComps[i];
            if (h == null) continue;

            // Health ring fill
            float maxHP = h.maxHealth > 0 ? h.maxHealth : 100f;
            float pct   = Mathf.Clamp01((float)h.currentHealth / maxHP);

            if (i < healthDialImages.Count && healthDialImages[i] != null)
            {
                healthDialImages[i].fillAmount = pct;
                healthDialImages[i].color      = Color.Lerp(healthLowColor, healthFullColor, pct);
            }

            // Dead overlay
            bool dead = h.isDead;
            if (i < deadOverlays.Count && deadOverlays[i] != null)
            {
                if (deadOverlays[i].activeSelf != dead)
                    deadOverlays[i].SetActive(dead);
            }

            // Disable click on dead characters
            if (i < characterPortraits.Count && characterPortraits[i] != null)
            {
                Button btn = characterPortraits[i].GetComponent<Button>();
                if (btn != null) btn.interactable = !dead;
            }
        }
    }

    // ─── Events ──────────────────────────────────────────────

    private void OnCharacterSwitched(GameObject oldChar, GameObject newChar)
    {
        if (newChar == null) return;
        for (int i = 0; i < _characters.Count; i++)
        {
            if (_characters[i] == newChar)
            {
                SetHighlight(i);
                return;
            }
        }
    }

    private void SetHighlight(int index)
    {
        // Remove old highlight
        if (_currentHighlight >= 0 && _currentHighlight < highlightBorders.Count
            && highlightBorders[_currentHighlight] != null)
        {
            highlightBorders[_currentHighlight].color = defaultBorderColor;
        }
        if (_currentHighlight >= 0 && _currentHighlight < characterPortraits.Count
            && characterPortraits[_currentHighlight] != null)
        {
            characterPortraits[_currentHighlight].transform.localScale = Vector3.one;
        }

        _currentHighlight = index;

        // Apply new highlight
        if (index >= 0 && index < highlightBorders.Count && highlightBorders[index] != null)
        {
            highlightBorders[index].color = highlightColor;
        }
        if (index >= 0 && index < characterPortraits.Count && characterPortraits[index] != null)
        {
            characterPortraits[index].transform.localScale = Vector3.one * 1.1f;
        }
    }

    private void OnSlotClicked(int index)
    {
        if (index < 0 || index >= _characters.Count) return;
        if (index < _healthComps.Count && _healthComps[index] != null && _healthComps[index].isDead) return;
        if (index == _currentHighlight) return;

        // Play switch SFX
        if (switchSFX != null && _audio != null)
            _audio.PlayOneShot(switchSFX, sfxVolume);

        CashSystemManager mgr = CashSystemManager.Instance;
        if (mgr != null)
        {
            mgr.SwitchToCharacterAtIndex(index);
        }
    }

    private void HideImmediate()
    {
        _canvasGroup.alpha = 0f;
        _canvasGroup.blocksRaycasts = false;
        _canvasGroup.interactable = false;
    }

    // ─── Utility ─────────────────────────────────────────────

    private Sprite GetCharacterIcon(GameObject character)
    {
        if (character == null) return null;

        var ai = character.GetComponent<CharacterAIController>();
        if (ai != null)
        {
            var field = typeof(CharacterAIController)
                .GetField("characterStats",
                    System.Reflection.BindingFlags.NonPublic |
                    System.Reflection.BindingFlags.Instance);
            if (field != null)
            {
                CharacterStats stats = field.GetValue(ai) as CharacterStats;
                if (stats != null)
                {
                    if (stats.characterIcon != null)     return stats.characterIcon;
                    if (stats.characterPortrait != null)  return stats.characterPortrait;
                }
            }
        }

        string cleanName = character.name.Replace("(Clone)", "").Trim();
        return Resources.Load<Sprite>($"CharacterPortraits/{cleanName}");
    }

    private string GetCharacterName(GameObject character)
    {
        if (character == null) return "?";

        var ai = character.GetComponent<CharacterAIController>();
        if (ai != null)
        {
            var field = typeof(CharacterAIController)
                .GetField("characterStats",
                    System.Reflection.BindingFlags.NonPublic |
                    System.Reflection.BindingFlags.Instance);
            if (field != null)
            {
                CharacterStats stats = field.GetValue(ai) as CharacterStats;
                if (stats != null && !string.IsNullOrEmpty(stats.displayName))
                    return stats.displayName;
            }
        }

        return character.name.Replace("(Clone)", "").Trim();
    }
}
