// Assets/_Project/Scripts/Gameplay/EnemyStatus.cs
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;
using TD.Core;

namespace TD.Gameplay
{
    /// <summary>
    /// A single active lingering effect on an enemy.
    /// </summary>
    /// <remarks>
    /// <b>Magnitude semantics by source:</b>
    /// <list type="bullet">
    ///   <item>Cold   — fraction of speed retained (0.5 = half speed)</item>
    ///   <item>Fire   — damage per second applied as a DoT tick</item>
    ///   <item>Poison — damage per second applied as a DoT tick</item>
    ///   <item>Others — unused (magnitude = 0)</item>
    /// </list>
    /// <b>SourceOwner</b> carries the <see cref="PlayerSlot"/> of the tower that
    /// applied this effect so DoT kill credit goes to the right player.
    /// </remarks>
    public struct StatusEffect
    {
        public DamageType Source;
        public float      Magnitude;
        public float      RemainingDuration;
        public PlayerSlot SourceOwner;
    }

    /// <summary>
    /// Tracks and ticks lingering status effects (slow, burn, poison) on an enemy.
    /// </summary>
    /// <remarks>
    /// <b>Authority:</b> The active-effect list is server-local. Only the derived
    /// <see cref="speedMultiplier"/> NetworkVariable is replicated so
    /// <c>EnemyMovement</c> can scale speed on all peers.
    ///
    /// <b>Stacking rule:</b> Re-hitting with the same <see cref="DamageType"/>
    /// refreshes duration and magnitude; it does not stack. Cross-type interactions
    /// are not implemented; <see cref="HasEffect"/> is the hook for future work.
    ///
    /// <b>DoT damage</b> calls <see cref="EnemyHealth.TakeDamage"/> with the original
    /// <see cref="StatusEffect.SourceOwner"/> so kill attribution stays correct.
    /// </remarks>
    [RequireComponent(typeof(NetworkObject))]
    public class EnemyStatus : NetworkBehaviour
    {
        private readonly NetworkVariable<float> speedMultiplier = new NetworkVariable<float>(
            1f,
            NetworkVariableReadPermission.Everyone,
            NetworkVariableWritePermission.Server);

        private readonly List<StatusEffect> activeEffects = new List<StatusEffect>();

        private EnemyHealth health;

        // ----- NGO lifecycle -----------------------------------------------

        public override void OnNetworkSpawn()
        {
            health = GetComponent<EnemyHealth>();
        }

        // ----- Public API --------------------------------------------------

        /// <summary>Current speed fraction (0–1). 1 = full speed, 0.5 = half speed.</summary>
        public float GetSpeedMultiplier() => speedMultiplier.Value;

        /// <summary>True if an effect of the given type is currently active.</summary>
        public bool HasEffect(DamageType type)
        {
            for (int i = 0; i < activeEffects.Count; i++)
                if (activeEffects[i].Source == type) return true;
            return false;
        }

        /// <summary>
        /// Applies or refreshes a lingering effect. Server-only; no-op on clients.
        /// Re-hitting with the same source type refreshes duration and magnitude.
        /// <paramref name="owner"/> is the tower's <see cref="PlayerSlot"/> — carried
        /// on the effect so DoT ticks credit the right player on a kill.
        /// </summary>
        public void ApplyEffect(DamageType source, float magnitude, float duration,
                                PlayerSlot owner)
        {
            if (!IsServer) return;

            for (int i = 0; i < activeEffects.Count; i++)
            {
                if (activeEffects[i].Source != source) continue;

                var e = activeEffects[i];
                e.Magnitude         = magnitude;
                e.RemainingDuration = duration;
                e.SourceOwner       = owner;
                activeEffects[i]    = e;
                RecalculateSpeedMultiplier();
                return;
            }

            activeEffects.Add(new StatusEffect
            {
                Source            = source,
                Magnitude         = magnitude,
                RemainingDuration = duration,
                SourceOwner       = owner,
            });
            RecalculateSpeedMultiplier();
        }

        // ----- Server tick ------------------------------------------------

        private void Update()
        {
            if (!IsServer || activeEffects.Count == 0) return;
            TickEffects(Time.deltaTime);
        }

        private void TickEffects(float dt)
        {
            bool anyExpired = false;

            for (int i = activeEffects.Count - 1; i >= 0; i--)
            {
                var e = activeEffects[i];

                // DoT tick — pass the original source owner so kill credit is correct.
                if ((e.Source == DamageType.Fire || e.Source == DamageType.Poison)
                    && health != null && !health.IsDead)
                {
                    health.TakeDamage(e.Magnitude * dt, e.Source, e.SourceOwner);
                }

                e.RemainingDuration -= dt;
                if (e.RemainingDuration <= 0f)
                {
                    activeEffects.RemoveAt(i);
                    anyExpired = true;
                }
                else
                {
                    activeEffects[i] = e;
                }
            }

            if (anyExpired)
                RecalculateSpeedMultiplier();
        }

        private void RecalculateSpeedMultiplier()
        {
            float mult = 1f;
            for (int i = 0; i < activeEffects.Count; i++)
            {
                if (activeEffects[i].Source == DamageType.Cold)
                    mult = Mathf.Min(mult, activeEffects[i].Magnitude);
            }
            speedMultiplier.Value = mult;
        }
    }
}
