// Copyright © Selmo Technology GmbH. All Rights Reserved

using Microsoft.AspNetCore.Components;
using Novus.Connectivity.Common;
using SelmoStudio.Hmi.Common.SelmoProject.Ids;
using SelmoStudio.Hmi.Common.SelmoProject.ProcessValue;
using SelmoStudio.Hmi.Server.ProcessValue.Services;
using SelmoStudio.Hmi.Server.SelmoHmi.Helpers;
using SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Model;
using SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Model.Dto;
using SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Model.Ids;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.Component;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.Component.CustomArgs;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.TestImpl;
using SelmoStudio.Hmi.Server.Shared.Resources;

namespace SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Components
{
    public partial class SequenceTimeComponent : IBaseProcessValueComponent, IAsyncDisposable
    {
        private string[] _columnHeaders;
        private Dictionary<StepId, List<IProcessValue>> _lookupTable = new();
        private Dictionary<StepId, ProcessValueMonitoringStep> _lookupTableProcessValueInfos = new();
        private IProcessValue _teachMode;
        private ProjectItemCollectionSequence _sequence;
        private List<StepDto> _orderedSteps;

        [Parameter]
        public ProjectItemCollectionSequence Sequence { get; set; } = new();

        [Parameter]
        public Dictionary<SelmoHmiStepId, int> StepOrder { get; set; }

        [Inject]
        private IProcessValueInfoService _processValueInfoService { get; set; }

        [Inject]
        private ILogger<SequenceTimeComponent> _logger { get; set; }

        #region Init/Lifecycle

        protected override Task OnInitializedAsync()
        {
            GenerateColumnHeaders();

            return base.OnInitializedAsync();
        }

        protected override Task OnParametersSetAsync()
        {
            if (_sequence == null || _sequence != Sequence)
            {
                _sequence = Sequence;
                _orderedSteps = GetOrderedSteps();
                _logger.LogInformation("Changed Sequence Content");
            }

            return base.OnParametersSetAsync();
        }

        private bool _isRendered;

        public bool IsRendered
        {
            get
            {
                return _isRendered;
            }
        }

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            await base.OnAfterRenderAsync(firstRender);
            _isRendered = true;
        }

        #endregion Init/Lifecycle

        private void GenerateColumnHeaders()
        {
            _columnHeaders = new[]
            {
                $"{HmiResource.Name}",
                $"{HmiResource.Actual}",
                $"{HmiResource.Last}",
                $"{HmiResource.Min}",
                $"{HmiResource.Avg}",
                $"{HmiResource.Max}",
                $"{HmiResource.TimeoutCount}",
                $"{HmiResource.Timeout}",
                $"{HmiResource.TimeoutAdd}",
                $"{HmiResource.DisableTimeout}",
            };
        }

        private void HandleValue(IProcessValue value)
        {
            if (value.ValueInfo.Id.Guid.Equals(_teachMode.ValueInfo.Id.Guid))
            {
                _teachMode = new TestValuesForDemo.TestProcessValue()
                {
                    Value = value.Value,
                    ValueInfo = _teachMode.ValueInfo
                };
                return;
            }
            var correctValue = GetMatchingProcessValue(value.ValueInfo.Id);
            if (correctValue.Item2 != null)
            {
                _lookupTable[correctValue.Item1].Remove(correctValue.Item2);
                var newValue = new TestValuesForDemo.TestProcessValue()
                {
                    Value = value.Value,
                    ValueInfo = correctValue.Item2.ValueInfo
                };
                _lookupTable[correctValue.Item1].Add(newValue);
            }
        }

        private (StepId, IProcessValue) GetMatchingProcessValue(ProcessValueId id)
        {
            (StepId, IProcessValue) value = (new(Guid.Empty), null);
            foreach (var processValueList in _lookupTable)
            {
                var foundValue = processValueList.Value.FirstOrDefault(p => p.ValueInfo.Id.Guid.Equals(id.Guid));
                if (foundValue != null)
                    value = (processValueList.Key, foundValue);
            }
            return value;
        }

        private List<IProcessValue> GetMatchingProcessValues(Guid id)
        {
            if (_lookupTable.Count == 0)
                return new List<IProcessValue>();
            var sId = _lookupTable.Keys.FirstOrDefault(k => k.Guid.Equals(id));
            if (sId.Guid.Equals(Guid.Empty))
                return new();
            return _lookupTable[sId];
        }

        private ProcessValueMonitoringStep GetProcessValuesMonitoringStep(StepId id)
        {
            if (_lookupTable.Count == 0)
                return new();

            if (!_lookupTableProcessValueInfos.ContainsKey(id))
                return new();

            return _lookupTableProcessValueInfos[id];
        }

        private ProcessValueHandleInfo GetValueInfo(ProcessValueId id)
        {
            if (id.Equals(_teachMode.ValueInfo.Id))
                return new ProcessValueHandleInfo()
                {
                    ProcessValueHandle = ProcessValueHandle.SetValue,
                    ProcessValueInfo = _teachMode.ValueInfo,
                    Value = !bool.Parse(_teachMode.Value.ToString())
                };

            return null;
        }

        private void TriggerComponentChangeEvent(ButtonEventArgs e, ProcessValueId id)
        {
            if (e == null)
                return;
            var processValueHandleInfo = GetValueInfo(id);
            if (processValueHandleInfo == null)
                return;

            ComponentChangeEvent?.Invoke(this, ComponentEventArgs.Create(e, processValueHandleInfo));
        }

        #region ComponentHandling

        public event EventHandler<ComponentEventArgs> ComponentChangeEvent;

        public List<IProcessValueInfo> GetValueInfos()
        {
            if (!IsRendered)
                return new();

            if (_sequence == null || _sequence.SequenceInfo == null)
            {
                return new();
            }

            var values = _processValueInfoService
                .CreateStepMonitoringRegistration(_sequence.SequenceInfo.Id).ValueInfos;
            _lookupTable = _processValueInfoService
                .GetProcessValueLookUpMonitoringSteps(_sequence.SequenceInfo.Id);
            _lookupTableProcessValueInfos = _processValueInfoService
                .GetProcessValueInfoLookUpMonitoringSteps(_sequence.SequenceInfo.Id);
            _teachMode = _processValueInfoService
                .GetTeachMode(_sequence.SequenceInfo.Id);

            _readProcessValues = values.ToList();
            return values.ToList();
        }

        private List<IProcessValueInfo> _readProcessValues = new();

        public void Update(IDictionary<ProcessValueId, IProcessValue> updatedValues)
        {
            if (!IsRendered)
                return;

            foreach (var processValue in _readProcessValues)
            {
                if (updatedValues.ContainsKey(processValue.Id))
                {
                    HandleValue(updatedValues[processValue.Id]);
                }
            }
        }

        private void SubpageComponentEventTriggered(object? sender, ComponentEventArgs e)
        {
            ComponentChangeEvent?.Invoke(sender, e);
        }

        #endregion ComponentHandling

        private List<StepDto> GetOrderedSteps()
        {
            var orderedSteps = Sequence.StepCollection.Steps.OrderBy(s =>
            {
                var key = StepOrder.Keys.FirstOrDefault(k => k.Guid.Equals(s.Id.Guid));
                return key != null ? StepOrder[key] : int.MaxValue;
            });

            return orderedSteps.ToList();
        }

        private string GetTeachButtonBackgroundColor()
        {
            if (_teachMode == null)
                return HtmlStyleHelper.GetToggleButtonBackgroundColor(false);
            var teachButtonValue = (bool)_teachMode.Value;

            return HtmlStyleHelper.GetToggleButtonBackgroundColor(teachButtonValue);
        }

        private string GetStepName(StepDto step)
        {
            var hmiText = step.HmiDisplayText.Trim();
            if (!string.IsNullOrEmpty(hmiText))
            {
                return hmiText;
            }

            return step.Name;
        }

        public async ValueTask DisposeAsync()
        {
        }
    }
}