using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace BingoBrain.Core
{
    public class Psvsagh
    {
        private Psvsa _psvsa;

        public int repeatCount;
        public float interval;
        private Action<Psvsagh> onCallBack;
        public object[] args;
        public float time;
        public bool isActive = true;
        public bool isFrameUpdate = false;

        public Psvsagh(Psvsa psvsa, float interval, Action<Psvsagh> onCallBack, params object[] args)
        {
            this._psvsa = psvsa;

            repeatCount = 1;
            this.interval = interval;
            this.onCallBack = onCallBack;
            this.args = args;
            time = psvsa.GetTriggerTime(interval);
        }

        public Psvsagh(Psvsa psvsa, int repeatCount, float interval, Action<Psvsagh> onCallBack,
            params object[] args)
        {
            this._psvsa = psvsa;

            this.repeatCount = repeatCount;
            this.interval = interval;
            this.onCallBack = onCallBack;
            this.args = args;
            time = psvsa.GetTriggerTime(interval);
        }

        public Psvsagh(Psvsa psvsa, Action<Psvsagh> onCallBack, params object[] args)
        {
            this._psvsa = psvsa;

            this.onCallBack = onCallBack;
            this.args = args;
        }

        public void SetActive(bool isActive)
        {
            if (this.isActive == isActive) return;

            this.isActive = isActive;
            if (!isFrameUpdate)
            {
                if (this.isActive)
                {
                    time = _psvsa.GetTriggerTime(interval);
                }
            }
        }

        public void CallFunc()
        {
            onCallBack?.Invoke(this);
        }

        public void Kill(bool needComplete = false)
        {
            if (needComplete)
            {
                CallFunc();
            }

            Dispose();
        }

        public void Dispose()
        {
            _psvsa.RemoveTimer(this);
        }

        public static implicit operator bool(Psvsagh psvsagh)
        {
            return null != psvsagh;
        }
    }

    public class Psvsa : MonoBehaviour
    {
        public const int INFINITE_LOOP = -1;

        private List<Psvsagh> timerTaskList = new();
        private List<Psvsagh> timerTaskTriggers = new();

        [SerializeField] private string timerName;
        private TimerTimeType type = TimerTimeType.Null;

        public void SetTimer(string name, TimerTimeType type)
        {
            this.timerName = name + "_" + type;
            this.type = type;
        }

        private float GetTime()
        {
            return type switch
            {
                TimerTimeType.Time => Time.time,
                TimerTimeType.UnscaledTime => Time.unscaledTime,
                TimerTimeType.RealtimeSinceStartup => Time.realtimeSinceStartup,
                _ => 0
            };
        }

        private void Update()
        {
            if (timerTaskList.Count > 0)
            {
                timerTaskTriggers.Clear();
                foreach (var timerTask in timerTaskList.Where(timerTask => timerTask.isActive))
                {
                    if (timerTask.isFrameUpdate)
                    {
                        timerTaskTriggers.Add(timerTask);
                    }
                    else
                    {
                        if (timerTask.time <= GetTime())
                        {
                            timerTaskTriggers.Add(timerTask);
                        }
                    }
                }

                foreach (var triggerTimerTask in timerTaskTriggers)
                {
                    if (triggerTimerTask.repeatCount != INFINITE_LOOP)
                    {
                        triggerTimerTask.repeatCount--;
                    }

                    if (triggerTimerTask.repeatCount == 0)
                    {
                        timerTaskList.Remove(triggerTimerTask);
                    }
                    else
                    {
                        if (!triggerTimerTask.isFrameUpdate)
                        {
                            triggerTimerTask.time = GetTriggerTime(triggerTimerTask.interval);
                        }
                    }

                    triggerTimerTask.CallFunc();
                }
            }
        }

        public Psvsagh AddTimer(float interval, Action<Psvsagh> onCallBack, params object[] args)
        {
            var timeTask = new Psvsagh(this, interval, onCallBack, args);
            AddTimer(timeTask);
            return timeTask;
        }

        public Psvsagh AddRepeatTimer(int repeatCount, float interval, Action<Psvsagh> onCallBack,
            params object[] args)
        {
            var timeTask = new Psvsagh(this, repeatCount, interval, onCallBack, args);
            AddTimer(timeTask);
            return timeTask;
        }

        public Psvsagh AddLoopTimer(float interval, Action<Psvsagh> onCallBack, params object[] args)
        {
            var timeTask = new Psvsagh(this, INFINITE_LOOP, interval, onCallBack, args);
            AddTimer(timeTask);
            return timeTask;
        }

        public Psvsagh AddFrameUpdateTimer(Action<Psvsagh> onCallBack, params object[] args)
        {
            var timeTask = new Psvsagh(this, onCallBack, args)
            {
                repeatCount = INFINITE_LOOP,
                isFrameUpdate = true
            };
            AddTimer(timeTask);
            return timeTask;
        }

        public void AddTimer(Psvsagh psvsagh)
        {
            if (null != psvsagh)
            {
                if (!psvsagh.isFrameUpdate)
                {
                    if (psvsagh.interval <= 0)
                    {
                        psvsagh.CallFunc();
                        return;
                    }
                }

                timerTaskList.Add(psvsagh);
            }
        }

        public void RemoveTimer(Psvsagh psvsagh)
        {
            if (psvsagh == null) return;
            if (timerTaskList == null) return;
            if (timerTaskList.Count == 0) return;

            if (timerTaskList.Contains(psvsagh))
            {
                timerTaskList.Remove(psvsagh);
            }
        }

        public void ClearAll()
        {
            timerTaskList.Clear();
            timerTaskTriggers.Clear();
        }

        public void Destroy()
        {
            Destroy(this);
        }

        public float GetTriggerTime(float interval)
        {
            return GetTime() + interval;
        }

        private void OnDestroy()
        {
            ClearAll();
            timerTaskList = null;
            timerTaskTriggers = null;
        }
    }
}