using System;
using System.Collections.Generic;
using UnityEngine;
using GameFramework;

namespace IndianOceanAssets.Engine2_5D
{
    /// <summary>
    /// 灵灯系统 —— 挂在玩家物体上。
    /// 按 U 键在玩家当前位置放置灵灯，灵灯照亮周围区域，
    /// 怪物碰触灵灯会被扣 1 点血，灵灯消失并被回收。
    /// 灵灯有存在时间，超时后自动回收。
    /// </summary>
    public class SpiritLanternSystem : MonoBehaviour
    {
        [Header("灵灯数量")]
        [Tooltip("最大可持有灵灯数量")]
        [SerializeField] private int maxLanterns = 5;

        [Header("按键")]
        [SerializeField] private KeyCode lanternKey = KeyCode.U;

        [Header("冷却")]
        [Tooltip("放置灵灯的冷却时间（秒）")]
        [SerializeField] private float cooldown = 3.5f;

        [Header("灵灯预制体")]
        [SerializeField] private GameObject lanternPrefab;

        private int _remainingLanterns;
        private float _lastPlaceTime = -999f;

        /// <summary>跟踪所有已放置的灵灯，用于回收时取消事件订阅，防止内存泄漏</summary>
        private readonly List<SpiritLantern> _activeLanterns = new List<SpiritLantern>();

        /// <summary>当前可释放的灵灯数量（供 UI 使用）</summary>
        public int RemainingLanterns => _remainingLanterns;

        /// <summary>冷却是否就绪</summary>
        public bool IsCooldownReady => Time.time > _lastPlaceTime + cooldown;

        /// <summary>冷却剩余时间（供 UI 使用）</summary>
        public float CooldownRemaining => Mathf.Max(0f, (_lastPlaceTime + cooldown) - Time.time);

        /// <summary>冷却总时长（供 UI 计算 CD 比例，替代反射读取私有字段）</summary>
        public float Cooldown => cooldown;

        private void Start()
        {
            _remainingLanterns = maxLanterns;
        }

        private void Update()
        {
            // 按 U 或鼠标左键 且 CD 就绪 且 还有灵灯 → 放置
            if ((Input.GetKeyDown(lanternKey) || Input.GetMouseButtonDown(0))
                && _remainingLanterns > 0
                && Time.time > _lastPlaceTime + cooldown
                && lanternPrefab != null)
            {
                PlaceLantern();
            }
        }

        /// <summary>
        /// 在玩家当前位置放置一个灵灯。
        /// </summary>
        private void PlaceLantern()
        {
            _remainingLanterns--;
            _lastPlaceTime = Time.time;

            // 播放灵灯放置音效
            if (AudioManager.Instance != null)
                AudioManager.Instance.PlaySFXFromResources("SFX/Lantern", 0.8f);

            // 在玩家位置实例化灵灯
            GameObject lanternObj = Instantiate(lanternPrefab, transform.position, Quaternion.identity);
            SpiritLantern lantern = lanternObj.GetComponent<SpiritLantern>();

            if (lantern != null)
            {
                // 设置所有者引用，用于回收时取消事件订阅
                lantern.SetOwner(this);
                // 订阅灵灯回收事件，并跟踪该灵灯
                lantern.OnLanternRecalled += OnLanternRecalled;
                _activeLanterns.Add(lantern);
            }
        }

        /// <summary>
        /// 灵灯被回收时调用（怪物碰触或超时）。
        /// 清理已销毁的灵灯引用，防止内存泄漏。
        /// </summary>
        private void OnLanternRecalled()
        {
            // 清理列表中已销毁的灵灯引用
            _activeLanterns.RemoveAll(l => l == null);
            _remainingLanterns = Mathf.Min(_remainingLanterns + 1, maxLanterns);
        }

        /// <summary>
        /// 显式取消订阅指定灵灯的事件并从跟踪列表移除。
        /// 由 SpiritLantern 在销毁前调用，确保事件订阅被正确释放。
        /// </summary>
        public void UnregisterLantern(SpiritLantern lantern)
        {
            if (lantern != null)
            {
                lantern.OnLanternRecalled -= OnLanternRecalled;
                _activeLanterns.Remove(lantern);
            }
        }

        /// <summary>
        /// 安全网：玩家销毁或场景卸载时，清理所有灵灯的事件订阅。
        /// </summary>
        private void OnDestroy()
        {
            foreach (var lantern in _activeLanterns)
            {
                if (lantern != null)
                    lantern.OnLanternRecalled -= OnLanternRecalled;
            }
            _activeLanterns.Clear();
        }

        // ===== 编辑器可视化 =====
        private void OnDrawGizmosSelected()
        {
            // 绘制冷却指示
            if (Time.time < _lastPlaceTime + cooldown)
            {
                float remaining = (_lastPlaceTime + cooldown) - Time.time;
                float ratio = remaining / cooldown;
                Gizmos.color = new Color(1f, 0.6f, 0f, 0.3f);
                Gizmos.DrawWireSphere(transform.position, 1f * ratio);
            }
        }
    }
}
