using System;
using System.Threading.Tasks;
using Quadarax.Foundation.Core.Logging;

namespace Quadarax.Foundation.Core.Thread
{
    public class LoopWorker : AbstractWorker
    {
        #region *** Private fields ***
        private TimeSpan _defaultTimeout;
        private long _cntLimit;
        private Func<IWorkerContext?, Task>? _customIteration;
        private bool _isIterationRunning = false;
        #endregion

        #region *** Properties ***
        public long IterationsLimit { get; set; } = 0;
        public TimeSpan IterationsDelayBetween { get; set; } = TimeSpan.Zero;
        /// <summary>
        /// Defines if overlap iteration is allowed. If false, iteration is skipped if previous iteration is not finished.
        /// Default value is false.
        /// </summary>
        public bool AllowOverlap { get; set; } = false;
        #endregion

        #region *** Constructors ***
        public LoopWorker(IWorkerContext context) : base(context)
        {

        }
        public LoopWorker(string workerName, IWorkerContext? context) : base(workerName, context)
        {
        }
        public LoopWorker(string workerName) : base(workerName)
        {

        }
        public LoopWorker(string workerName, IWorkerContext? context, ILogger? logger = null) : base(workerName, context, logger)
        {
        }
        public LoopWorker(string workerName, IWorkerContext? context,Func<IWorkerContext?, Task>? customIteration = null, ILogger? logger = null) : base(workerName, context, logger)
        {
            _customIteration = customIteration;
        }
        #endregion

        #region *** Public Operations ***
        #endregion

        #region *** Virtuals and protected ***

        protected override async Task Do(IWorkerContext? context)
        {
            var exit = false;
            var first = true;
            while (!exit)
            {
                if (first)
                    first = false;
                else if (IterationsDelayBetween != TimeSpan.Zero)
                    await Task.Delay(IterationsDelayBetween);
                    //System.Threading.Thread.CurrentThread.Join(IterationsDelayBetween);

                if (_isIterationRunning && !AllowOverlap)
                {
                    await Task.Delay(100);
                    continue;
                }
                _isIterationRunning = true;
                if (IterationsLimit == 0)
                {
                    if (_customIteration != null)
                        await _customIteration(context);
                    else
                        await DoIteration(context);
                }
                else
                {
                    if (_customIteration != null)
                        await _customIteration(context);
                    else
                        await DoIteration(context);
                    _cntLimit++;
                    if (_cntLimit > IterationsLimit)
                        exit = true;
                }
                _isIterationRunning = false;
            }
        }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
        protected virtual async Task DoIteration(IWorkerContext? context)
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
        {
        }

        protected override void OnBeforeStart()
        {
            base.OnBeforeStart();
            _defaultTimeout = Timeout;
            Timeout = TimeSpan.Zero;
        }
        protected override void OnAfterStop()
        {
            base.OnAfterStop();
            Timeout = _defaultTimeout;
            _cntLimit = 0;
        }
        #endregion

        #region *** Private Operations ***
        #endregion

    }
}
