// Copyright © Selmo Technology GmbH. All Rights Reserved

using Microsoft.AspNetCore.Components.Web;
using Novus.Connectivity.Service;
using Novus.Shared.Types.Interval;
using SelmoStudio.Hmi.Server.Db.Context;
using SelmoStudio.Hmi.Server.ProcessValue.Model;

namespace SelmoStudio.Hmi.Server.ProcessValue.Services
{
    public class HistoryProcessValueCollector : IHistoryProcessValueCollector
    {
        public event EventHandler OnIntervallElapsed;

        public IntervalPolling<bool> _intervalPolling;

        private readonly IProcessValuePollingService _processValuePollingService;
        private readonly IProcessValueDbContext _context;

        public HistoryProcessValueCollector(IProcessValuePollingService processValuePollingService,
            ProcessValueDbContext context)
        {
            _processValuePollingService = processValuePollingService;
            _context = context;
        }

        public async Task Start(List<HistoryValueGroupSettings> collectionSettings)
        {
            await Register(collectionSettings);
            RestartIntervallPolling();
        }

        public async Task Register(List<HistoryValueGroupSettings> collectionSettings)
        {
            SetIntervalRange(collectionSettings);
            RegisterCollectors(collectionSettings);
        }

        #region Collectors

        private Dictionary<int, HistoryValueGroupCollector> _currentlyRunningCollectors = new();

        private void RegisterCollectors(List<HistoryValueGroupSettings> collectionSettings)
        {
            _currentlyRunningCollectors.Clear();
            foreach (var collsetting in collectionSettings)
            {
                RegisterCollector(collsetting);
            }
        }

        private void RegisterCollector(HistoryValueGroupSettings collsetting)
        {
            if (_currentlyRunningCollectors.ContainsKey(collsetting.GroupId))
                throw new ArgumentException($"{nameof(HistoryValueGroupSettings.GroupId)} must be unique.");

            HistoryValueGroupCollector collector = new HistoryValueGroupCollector(collsetting, _context);
            _currentlyRunningCollectors.Add(collsetting.GroupId, collector);
        }

        #endregion Collectors

        #region Intervall Handling

        private int _addTimeMs = 0;

        public int _minCollectionIntervall = 1000;
        public int _maxCollectionIntervall = 1000;
        public int _pollingIntervall = 1000;

        private bool RestartIntervallPolling()
        {
            try
            {
                if (_intervalPolling == null)
                {
                    _intervalPolling = new IntervalPolling<bool>(new Func<PollingInfo, Task<bool>>(OnUpdate));
                }

                _intervalPolling.Stop();
                _intervalPolling.SetInterval(_pollingIntervall);
                _intervalPolling.Start();
            }
            finally
            {
            }

            return true;
        }

        private void SetIntervalRange(List<HistoryValueGroupSettings> collectionSettings)
        {
            foreach (var collsetting in collectionSettings)
            {
                int collRate = (int)collsetting.CollectingRate;
                if (collRate < _minCollectionIntervall)
                    _minCollectionIntervall = collRate;
                if (collRate > _maxCollectionIntervall)
                    _maxCollectionIntervall = collRate;
            }
            _pollingIntervall = _minCollectionIntervall;
        }

        public const int CountLimit = 999_000_000;

        private void IncrementIntervalSum(int pollingIntervall)
        {
            if (_addTimeMs > CountLimit &&
                _addTimeMs % _maxCollectionIntervall == 0)
            {
                _addTimeMs += pollingIntervall;
                return;
            }
            _addTimeMs += pollingIntervall;
        }

        private bool IsCollectorReadyWrite(HistoryValueGroupCollector collector)
        {
            if (_addTimeMs % collector.CollectionRateInMs == 0)
            {
                return true;
            }

            return false;
        }

        #endregion Intervall Handling

        #region Cyclic Update

        internal async Task<bool> OnUpdate(PollingInfo info)
        {
            /*
            var opResult = await _processValuePollingService.GetAllValues();

            if (opResult.Issues.Any())
                return false;

            UpdateCollectors(info, opResult.Value);

            if (OnIntervallElapsed != null)
            {
                ProgressEventArgs args = new ProgressEventArgs();
                OnIntervallElapsed(this, args);
            }

            return true;
            */
            return true;
        }

        private void UpdateCollectors(PollingInfo info, ValueInfo valueInfo)
        {
            foreach (var collector in _currentlyRunningCollectors)
            {
                if (IsCollectorReadyWrite(collector.Value))
                {
                    collector.Value.WriteValues(info.LastExecution, valueInfo, _context);
                }
            }
            IncrementIntervalSum(_pollingIntervall);
        }

        #endregion Cyclic Update
    }
}