using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Fort23.UTool;


namespace Fort23.Core
{
    public enum AwaiterStatus
    {
        Pending,
        Succeeded,
        Faulted,
    }

    /// <summary>
    /// 这是一个同步等待异步的框架, 如果要使用真正的异步，请使用Task
    /// A
    /// </summary>
    [AsyncMethodBuilder(typeof(AsyncTaskMethodBuilder))]
    public class CTask : ICTaskResult, IAwaitable<CTask>, IAwaiter
    {
        private Action _continuation;
        private AwaiterStatus state;
        private Exception _exception;
        private static readonly Queue<CTask> queue = new Queue<CTask>();
        public int currIndex = 0;
        static int allIndex = 0;
        public static bool isHindPool=false;

        /// <summary>
        /// 创建 <see cref="CTask{T}"/> 的新实例，并得到一个可以用于报告操作执行完毕的委托。
        /// </summary>
        /// <returns>
        /// 创建好的 <see cref="CTask{T}"/> 的新实例，将此返回值作为方法的返回值可以让方法支持 await 异步等待。
        /// </returns>
        public static CTask Create(bool isPool=true)
        {
#if !COMBAT_SERVER
            

            lock (queue)
            {
                if (queue.Count == 0||!isPool||isHindPool)
                {
                    CTask cTask = new CTask();
                    allIndex++;
                    cTask.currIndex = allIndex;
                    return cTask;
                }

                CTask value = queue.Dequeue();
                value.state = AwaiterStatus.Pending;
                return value;
            }
#endif
            return  new CTask();
            // var task = new CTask();
            // return task;
        }

        private CTask()
        {
        }

        public CTask GetAwaiter()
        {
            return this;
        }

        public bool IsCompleted
        {
            get { return this.state != AwaiterStatus.Pending; }
        }

        public void OnCompleted(Action continuation)
        {
            if (IsCompleted)
            {
                continuation?.Invoke();
            }
            else
            {
                _continuation += continuation;
            }
        }

        // private T Result { get; set; }

        /// <summary>
        /// 这个方法在return await CTask的时候自动调用
        /// </summary>
        public void GetResult()
        {
            if (_exception != null)
            {
                ExceptionDispatchInfo.Capture(_exception).Throw();
            }

            Recycle();
        }

        /// <summary>
        /// 调用此方法以报告任务结束，并指定返回值和异步任务中的异常。
        /// 当使用 <see cref="Create"/> 静态方法创建此类型的实例后，调用方可以通过方法参数中传出的委托来调用此方法。
        /// </summary>
        /// <param name="exception">异步操作中的异常。</param>
        public void SetResult(Exception exception = null)
        {
            _exception = exception;
            if (AwaiterStatus.Faulted == state)
            {
                return;
            }

            this.state = AwaiterStatus.Succeeded;
            if (_continuation != null)
            {
                _continuation.Invoke();
            }
        }

        public void SetResult()
        {
            SetResult(null);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exception"></param>
        public void SetException(Exception exception)
        {
            this.state = AwaiterStatus.Faulted;
            _exception = exception;
            LogTool.Error(_exception);
        }

        private void Recycle()
        {
            _continuation = null;
            _exception = null;
            if (state == AwaiterStatus.Pending)
            {
                return;
            }

            this.state = AwaiterStatus.Pending;
#if !COMBAT_SERVER
            lock (queue)
            {
                // 太多了
                if (queue.Count > 300||isHindPool)
                {
                    return;
                }

                if (queue.Contains(this))
                {
                    return;
                }

                queue.Enqueue(this);
            }
#endif
        }

        public override async Task AwaitTask()
        {
            await this;
        }
    }

    /// <summary>
    /// 这是一个同步等待异步的框架, 如果要使用真正的异步，请使用Task
    /// A
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [AsyncMethodBuilder(typeof(AsyncTaskMethodBuilder<>))]
    public class CTask<T> : ICTaskResult, IAwaitable<CTask<T>, T>, IAwaiter<T>
    {
        private Action _continuation;
        private AwaiterStatus state;
        private Exception _exception;
#if !COMBAT_SERVER
        private static readonly Queue<CTask<T>> queue = new Queue<CTask<T>>();
#endif
        public static bool isHindPool=false;
        /// <summary>
        /// 创建 <see cref="CTask{T}"/> 的新实例，并得到一个可以用于报告操作执行完毕的委托。
        /// </summary>
        /// <returns>
        /// 创建好的 <see cref="CTask{T}"/> 的新实例，将此返回值作为方法的返回值可以让方法支持 await 异步等待。
        /// </returns>
        public static CTask<T> Create(bool isPool=true)
        {
#if !COMBAT_SERVER
            lock (queue)
            {
                if (queue.Count == 0||!isPool||isHindPool)
                {
                    return new CTask<T>();
                }

                CTask<T> value = queue.Dequeue();
                value.state = AwaiterStatus.Pending;
                return value;
            }
#endif
            return new CTask<T>();
            // var task = new CTask<T>();
            // return task;
        }

        private CTask()
        {
        }

        public CTask<T> GetAwaiter()
        {
            return this;
        }

        public bool IsCompleted
        {
            get { return state != AwaiterStatus.Pending; }
        }

        public void OnCompleted(Action continuation)
        {
            if (IsCompleted)
            {
                continuation?.Invoke();
            }
            else
            {
                _continuation += continuation;
            }
        }

        private T _result;

        public T Result
        {
            get { return _result; }
        }

        /// <summary>
        /// 这个方法在return await CTask的时候自动调用
        /// </summary>
        /// <returns></returns>
        public T GetResult()
        {
            if (_exception != null)
            {
                ExceptionDispatchInfo.Capture(_exception).Throw();
            }

            Recycle();

            return _result;
        }

        /// <summary>
        /// 调用此方法以报告任务结束，并指定返回值和异步任务中的异常。
        /// 当使用 <see cref="Create"/> 静态方法创建此类型的实例后，调用方可以通过方法参数中传出的委托来调用此方法。
        /// </summary>
        /// <param name="result">异步返回值。</param>
        /// <param name="exception">异步操作中的异常。</param>
        public void SetResult(T result, Exception exception = null)
        {
            _result = result;
            _exception = exception;
            if (this.state == AwaiterStatus.Faulted)
            {
                return;
            }
            this.state = AwaiterStatus.Succeeded;
            if (_continuation != null)
            {
                _continuation.Invoke();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exception"></param>
        public void SetException(Exception exception)
        {
            this.state = AwaiterStatus.Faulted;
            _exception = exception;
            LogTool.Error(_exception);
        }

        private void Recycle()
        {
            _continuation = null;
            _exception = null;
            if (state == AwaiterStatus.Pending)
            {
                return;
            }

            this.state = AwaiterStatus.Pending;
#if !COMBAT_SERVER
            lock (queue)
            {
                // 太多了，回收一下
                if (queue.Count > 300||isHindPool)
                {
                    return;
                }

                if (queue.Contains(this))
                {
                    return;
                }

                queue.Enqueue(this);
            }
#endif
        }

        public override async Task AwaitTask()
        {
            await this;
        }
    }
}