// Assets/_Project/Scripts/Gameplay/ActiveBuff.cs
using System;
using Unity.Collections;
using Unity.Netcode;
using TD.Core;

namespace TD.Gameplay
{
    /// <summary>
    /// One buff currently held by a player. Stored in
    /// <see cref="PlayerBuffManager"/>'s NetworkList so all peers see the same set.
    /// </summary>
    /// <remarks>
    /// <para><b>IEquatable.</b> NGO's NetworkList indexer setter short-circuits when
    /// Equals returns true, silently dropping the write. Every mutable field
    /// (only <see cref="IsActive"/>) is included in the comparison so toggling a
    /// buff correctly propagates to clients.</para>
    /// </remarks>
    public struct ActiveBuff : INetworkSerializable, IEquatable<ActiveBuff>
    {
        /// <summary>Which tower stat this buff multiplies.</summary>
        public BuffStat Stat;

        /// <summary>Multiplicative factor, e.g. 1.25 for +25%.</summary>
        public float Multiplier;

        /// <summary>
        /// False when disabled (e.g. by an enemy ability). Excluded from
        /// <see cref="PlayerBuffManager.GetMultiplier"/> while false.
        /// </summary>
        public bool IsActive;

        /// <summary>Human-readable name for the HUD buff list.</summary>
        public FixedString64Bytes DisplayName;

        // ----- INetworkSerializable ---------------------------------------

        public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
        {
            byte statByte = (byte)Stat;
            serializer.SerializeValue(ref statByte);
            Stat = (BuffStat)statByte;

            serializer.SerializeValue(ref Multiplier);
            serializer.SerializeValue(ref IsActive);
            serializer.SerializeValue(ref DisplayName);
        }

        // ----- IEquatable -------------------------------------------------

        public bool Equals(ActiveBuff other)
            => Stat == other.Stat
            && Multiplier == other.Multiplier
            && IsActive == other.IsActive
            && DisplayName == other.DisplayName;

        public override bool Equals(object obj) => obj is ActiveBuff other && Equals(other);

        public override int GetHashCode() => HashCode.Combine((int)Stat, Multiplier, IsActive);
    }
}
