/*
 * 基于时间轮的计时器
 * 1轮代表10秒
 */
using System;
using System.Collections.Generic;
using UnityEngine;

public interface ITimer
{
    /// <summary>
    /// 添加任务（秒）
    /// </summary>
    /// <param name="delayTime">执行时间为m_CurTimer + delayTime秒后执行</param>
    /// <param name="action"></param>
    /// return 为 定时器id
    int Push(object obj,float delayTime, Action action);
    /// <summary>
    /// 单位秒
    /// </summary>
    /// <param name="timer"></param>
    void Update(float timer);
    /// <summary>
    /// 释放
    /// </summary>
    void OnDispose();
    /// <summary>
    /// 得到当前计时器时间
    /// </summary>
    /// <returns></returns>
    float GetCurTimer();
}

public class TimerTask
{
    public float exTime;
    ////第几轮
    //public int round;
    public Action action;

    public object obj;

    public int id;

    public TimerTask(int id, float exTime, Action action, object obj)
    {
        this.id = id;
        this.exTime = exTime;
        this.action = action;
        this.obj = obj;
    }
}

public class TimeChunk
{
    List<TimerTask> m_Tasks = new List<TimerTask>();
    List<TimerTask> m_ToRemoves = new List<TimerTask>();

    //LinkedList<TimerTask> m_Tasks = new LinkedList<TimerTask>();
    //LinkedListNode<TimerTask> temp = null;

    public void Push(TimerTask action)
    {
        //m_Tasks.AddLast(action);
        m_Tasks.Add(action);
    }

    public void Check(float timer)
    {
        //temp = m_Tasks.First;
        //while (temp != null && temp.Next != null)
        //{
        //    temp = temp.Next;

        //    if (timer >= temp.Value.exTime)
        //    {
        //        temp.Value.action?.Invoke();
        //        m_Tasks.Remove(temp.Value);
        //    }
        //}

        if (m_Tasks.Count == 0)
            return;

        if (m_ToRemoves.Count > 0)
        {
            foreach (var item in m_ToRemoves)
            {
                m_Tasks.Remove(item);
            }
            m_ToRemoves.Clear();
        }

        for (int i = m_Tasks.Count - 1; i >= 0; --i)
        {
            if (timer >= m_Tasks[i].exTime)
            {
                if (m_Tasks[i].obj != null)
                {
                    m_Tasks[i].action?.Invoke();
                }
                m_Tasks[i].obj = null;
                m_Tasks[i].action = null;
                m_Tasks.RemoveAt(i);
            }
        }
    }

    public bool TryRemove(int id)
    {
        for (int i = m_Tasks.Count - 1; i >= 0; --i)
        {
            if (m_Tasks[i].id == id)
            {
                m_ToRemoves.Add(m_Tasks[i]);
                return true;
            }
        }
        return false;
    }
}

public class TimerServices : ITimer
{
    //时间轮分多少个区域
    int m_ChunkCount;

    float m_CurTimer = 0;
    public float curTimer => m_CurTimer;

    TimeChunk[] m_Chunks;

    object m_Lock = new object();

    /// <summary>
    /// 定时器id的生成
    /// </summary>
    int idGen;

    int GenID()
    {
        return ++idGen;
    }

    public TimerServices(int chunkCount = 10)
    {
        InitChunk(chunkCount);
    }

    void InitChunk(int chunkCount = 10)
    {
        this.m_ChunkCount = chunkCount;
        m_Chunks = new TimeChunk[chunkCount];
        for (int i = 0; i < chunkCount; ++i)
        {
            m_Chunks[i] = new TimeChunk();
        }
    }

    /// <summary>
    /// 添加任务（秒）
    /// </summary>
    /// <param name="delayTime">执行时间为m_CurTimer + delayTime秒后执行</param>
    /// <param name="action"></param>
    public int Push(object obj,float delayTime, Action action)
    {
        int id = GenID();
        float time = m_CurTimer + delayTime;
        //Debug.Log($"预计执行时间：{time},delayTime:{delayTime}");
        TimerTask task = new TimerTask(id, time, action, obj);

        lock (m_Lock)
        {
            if (m_Chunks != null)
                m_Chunks[UnityEngine.Mathf.FloorToInt((time) % m_ChunkCount)].Push(task);
        }

        return id;
    }

    /// <summary>
    /// 通过id移除计时器
    /// </summary>
    /// <param name="id"></param>
    public void TryRemove(int id)
    {
        if (m_Chunks != null)
        {
            for (int i = 0; i < m_Chunks.Length; ++i)
            {
                if (m_Chunks[i].TryRemove(id))
                    break;
            }
        }
    }

    /// <summary>
    /// 单位秒
    /// </summary>
    /// <param name="timer"></param>
    public void Update(float timer)
    {
        if (m_Chunks == null)
        {
            InitChunk();
        }

        m_CurTimer += timer;

        lock (m_Lock)
        {
            m_Chunks[UnityEngine.Mathf.FloorToInt((m_CurTimer) % m_ChunkCount)].Check(m_CurTimer);
        }
    }

    public void OnDispose()
    {
        m_Chunks = null;
    }

    public float GetCurTimer()
    {
        return m_CurTimer;
    }
}