using System.Threading;
using System.Threading.Tasks;
using Aitex.Core.RT.DataCollection.HighPerformance;
using Aitex.Core.RT.Event;
using Aitex.Core.Util;
using MECF.Framework.RT.Core.IoProviders;

namespace Aitex.Core.RT.IOCore
{
	public class DOAccessor : IOAccessor<bool>
    {
        private Task _tPulseGen;
        
		public DOAccessor(string name, int index, string address, bool isSimulator = false, bool disImmCache = false)
			: base(name, index, address, IOType.DO, isSimulator, disImmCache)
		{
			
		}
		
		/// <inheritdoc />
		protected override void SetValue(int offset, bool value)
		{
			SetValue(value, out _);
		}
        
		public bool SetValue(bool value, out string reason)
		{
			if (IO.CanSetDO(Name, value, out reason))
			{
				var provider = Singleton<IoProviderManager>.Instance.GetProvider(base.Provider);
				if (provider != null && !provider.SetValue(this, value))
				{
					reason = "Write DO[" + Name + "] failed";
					return false;
				}

				var oldValue = Buffer[BlockOffset];
				Buffer[BlockOffset] = value;
				
				// Check if immediate cache needed
				var needImmCache = oldValue != value & !IsSimulator & !DisableImmediatelyCache;
                if (needImmCache)
                    DataTraceManager.Instance.ImmediateCache(this, new CacheDiagnosisInfo("", Name, Type, Index,
	                    value.ToString()));
                return true;
			}
			return false;
		}

		public bool SetPulseValue(bool value, out string reason, bool holdValue, int delayMillisecond)
		{
            //Debug.Assert(_tPulseGen == null || _tPulseGen.IsCompleted, $"DO {name} The last pulse is not finished.");

			if (IO.CanSetDO(Name, value, out reason))
            {
                if (_tPulseGen is { IsCompleted: false })
                {
                    // reason = $"{name} is busy generating pulse";
                    return true;
                }

                // Check if immediate cache needed
                var needImmCache = !IsSimulator & !DisableImmediatelyCache;
                
                _tPulseGen = Task.Run(() =>
                {
	                var oldValue = Value;
                    Value = value;
                    
                    // Check if immediate cache needed
                    needImmCache &= oldValue != value;
                    if (needImmCache)
	                    DataTraceManager.Instance.ImmediateCache(this, new CacheDiagnosisInfo("", Name, Type, Index,
		                    value.ToString()));

                    Thread.Sleep(delayMillisecond);
                    if (IO.CanSetDO(Name, holdValue, out var reason))
                    {
	                    oldValue = Value;
                        Value = holdValue;
                        // Check if immediate cache needed
                        needImmCache &= oldValue != value;
                        if (needImmCache)
	                        DataTraceManager.Instance.ImmediateCache(this, new CacheDiagnosisInfo("", Name, Type, Index,
		                        value.ToString()));
                    }
                    else
						EV.PostAlarmLog("", $"Unable to restore level of {Name}, {reason}");
                });
                
				return true;
			}
            
			return false;
		}

		public bool Check(bool value, out string reason)
		{
			return IO.CanSetDO(Name, value, out reason);
		}

		
	}
}
