using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using UnityEngine;
using VOID.Generic.Objects.Abstract.Events;
using VOID.Generic.Objects.Unit;
using VOID.ScriptableObjects;

namespace VOID.Generic.Objects.Abstract
{
    [System.Serializable]
    public class AbstractObjectStatusManager : ObjectComponent<AbstractObject>
    {
        #region Initialize

        protected override void EventInitialize()
        {
            // When realtime based gameplay is working
            parent.basicEvents.onFixedUpdate.AddListener(OnRealTimeDecreaseDuration);
            
            // When turn based gameplay is working
            parent.basicEvents.onTurnSelfStart.AddListener(OnTurnSelfStart);
            parent.basicEvents.onTurnSelfEnd.AddListener(OnTurnSelfEnd);
            
            // When entering or leaving turn based gameplay
            parent.basicEvents.onTurnQueueEnter.AddListener(OnTurnEnter);
            parent.basicEvents.onTurnQueueLeave.AddListener(OnTurnLeave);
        }

        protected override void Initialize()
        {
            // Statuses already added via inspector need to be started this way
            // Important thing - instantiate ScriptableObjects so we wont change original ones
            for (var i = 0; i < statuses.Count; i++)
            {
                statuses[i] = Object.Instantiate(statuses[i]);
                statuses[i].Init(parent);
                statuses[i].Apply();
            }
        }

        #endregion
        
        [SerializeReference, DisableInPlayMode] private List<BasicStatus> statuses = new();

        private void OnTurnEnter(TurnEvent turnEvent) => parent.basicEvents.onFixedUpdate.RemoveListener(OnRealTimeDecreaseDuration);
        private void OnTurnLeave(TurnEvent turnEvent) => parent.basicEvents.onFixedUpdate.AddListener(OnRealTimeDecreaseDuration);
        private void OnTurnSelfStart(TurnEvent turnEvent) => statuses.ForEach(status => status.OnTurnSelfStart());
        private void OnTurnSelfEnd(TurnEvent turnEvent) => statuses.ToList().ForEach(status => status.OnTurnSelfEnd());
        private void OnRealTimeDecreaseDuration() => statuses.ToList().ForEach(status => status.DecreaseDurationRealTime());

        public void AddStatus(BasicStatus status, UnitObject source = null, bool instantiate = true)
        {
            // instantiate ScriptableObjects so we wont change original ones if needed
            if (instantiate) status = Object.Instantiate(status);
            
            statuses.Add(status);
            status.Init(parent, source);
            status.Apply();
        }

        public void RemoveStatus(BasicStatus status) => statuses.Remove(status);

        public BasicStatus[] GetStatuses() => statuses.ToArray();
    }
}
