using System;
using System.Linq;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps.Filters
{
    public class MoveAverageFilter : FilterBase
    {
        #region Variables

        private readonly R_TRIG _rTrigFilterError = new R_TRIG();

        #endregion

        #region Constructor

        public MoveAverageFilter(string module, string filterName, string scBasePath)
            : base(module, filterName, scBasePath)
        {
            
        }

        #endregion

        #region Properties

        public int WindowSize { get; set; }

        #endregion

        public override bool Initialize(out string reason)
        {
            reason  = string.Empty;

            DATA.Subscribe($"{FilterName}.WindowSize", () => WindowSize);

            var scName = $"{ScBase}.WindowSize";
            WindowSize = SC.GetValue(scName, 0);
            SC.RegisterValueChangedCallback(scName, value =>
            {
                if(value is int winSize)
                    WindowSize = winSize;
                else
                    LOG.Warning($"{FilterName} Invalid value for MAF WindowSize: {value}. Expected an integer.");
            });

            return true;
        }

        protected override double HandleFilter(double lastTemp)
        {
            // make sure that minimal window size is 1.
            if (WindowSize < 0)
                WindowSize = 0;

            var lastData = DataBuffer.LastOrDefault();
            if (lastData == null)
                throw new NullReferenceException("Unable to find last temp data in DataBuffer.");

            try
            {
                if (WindowSize <= 0)
                    return lastData.Value;

                var filterRange = lastData.TimeStamp - TimeSpan.FromMilliseconds(WindowSize).Ticks;
                var filteredTemp = lastData.Value;

                // Remove old data points that are outside the filter range
                while (DataBuffer.Count > 0 && DataBuffer.Peek().TimeStamp < filterRange)
                    DataBuffer.Dequeue();
                
                var ave = DataBuffer.Average(x => x.Value);

                if (!double.IsNaN(ave) && !double.IsInfinity(ave))
                    filteredTemp = ave;

                _rTrigFilterError.CLK = false;
                return filteredTemp;
            }
            catch (Exception ex)
            {
                _rTrigFilterError.CLK = true;
                if (_rTrigFilterError.Q)
                    LOG.Error($"{FilterName} Unable to perform MAF, {ex.Message}.");
                return lastData.Value;
            }

        }
    }
}
