// Copyright © Selmo Technology GmbH. All Rights Reserved

using Microsoft.AspNetCore.Components;
using Novus.Connectivity.Common;
using SelmoStudio.Hmi.Common.SelmoProject.ProcessValue;
using SelmoStudio.Hmi.Server.ProcessValue.Services;
using SelmoStudio.Hmi.Server.SelmoHmi.ProjectInformation.Service;
using SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Model;
using SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Model.Ids;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.Component;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.Mappers;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.Model;
using System.Collections.Concurrent;

namespace SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Components
{
    public partial class SequenceListViewComponent : IBaseProcessValueComponent, IAsyncDisposable
    {
        [Inject]
        private IProjectInformationService _projectInformationService { get; set; }

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

        [Parameter]
        public string Id { get; set; }

        [Parameter]
        public IReadOnlyList<ProjectItemCollectionSequence> Sequences { get; set; }

        public IReadOnlyList<ProjectItemCollectionSequence> _sequences { get; set; }

        #region Init/Lifecycle

        protected override async Task OnParametersSetAsync()
        {
            if (Sequences != _sequences)
            {
                _sequences = Sequences;
            }

            await base.OnParametersSetAsync();
        }

        private bool _isRendered;

        public bool IsRendered
        {
            get
            {
                return _isRendered;
            }
        }

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

        #endregion Init/Lifecycle

        private void ClickedOnSequence(ProjectItemCollectionSequence sequence)
        {
            _projectInformationService.SelectSequence(sequence);
        }

        #region Handle ProcessValues

        private Dictionary<SequenceId, ProcessValuesSequenceStatus> _lookUpTableSeqStatus = new();

        private ConcurrentDictionary<SequenceId, List<IProcessValueInfo>> _lookUpTableSeqOverview = new();
        private Dictionary<ProcessValueId, IProcessValue> _lookUpTableSeqOverviewValues = new();
        private Dictionary<SequenceId, ProcessValuesSequence> _lookUpTableSeqProcessValueInfos = new();

        private List<string> GetIconList(ProjectItemCollectionSequence seq)
        {
            if (!_statusIcons.ContainsKey(seq.SequenceInfo.Id))
            {
                return new();
            }

            return _statusIcons[seq.SequenceInfo.Id];
        }

        #region Status

        private OperationMode GetLedStatus(ProjectItemCollectionSequence seqInfo)
        {
            if (_lookUpTableSeqStatus == null || !_lookUpTableSeqStatus.ContainsKey(seqInfo.SequenceInfo.Id))
            {
                return OperationMode.Error;
            }

            var infos = _lookUpTableSeqStatus[seqInfo.SequenceInfo.Id];
            Dictionary<ProcessValueId, IProcessValue> values = _lookUpTableSeqOverviewValues;
            return StatusHelper.GetOperationMode(infos, values);
        }

        private Dictionary<SequenceId, List<string>> _statusIcons = new();

        private void UpdateSequencesIconState(IDictionary<ProcessValueId, IProcessValue> currentValues)
        {
            Dictionary<SequenceId, List<string>> states = new();
            foreach (var seq in Sequences)
            {
                if (states.ContainsKey(seq.SequenceInfo.Id))
                {
                    states.Add(seq.SequenceInfo.Id, new());
                }
                states[seq.SequenceInfo.Id] = UpdateSequenceIconState(seq, currentValues);
            }
            _statusIcons = states;
        }

        private List<string> UpdateSequenceIconState(ProjectItemCollectionSequence seq, IDictionary<ProcessValueId, IProcessValue> currentValues)
        {
            var seqInfo = seq.SequenceInfo;
            if (_lookUpTableSeqOverview == null)
                return new();

            if (!_lookUpTableSeqOverview.ContainsKey(seqInfo.Id))
                return new();

            var iconList = new List<IProcessValueInfo>();
            foreach (var info in _lookUpTableSeqOverview[seqInfo.Id])
            {
                if (_lookUpTableSeqOverviewValues.ContainsKey(info.Id))
                {
                    var processValue = _lookUpTableSeqOverviewValues[info.Id];
                    if (processValue.ValueInfo.DataType.Equals(typeof(bool)))
                    {
                        if (_lookUpTableSeqOverviewValues[info.Id].Value != null)
                        {
                            var pv = _lookUpTableSeqOverviewValues[info.Id];

                            if (currentValues.ContainsKey(pv.ValueInfo.Id))
                            {
                                var currentValue = currentValues[pv.ValueInfo.Id];
                                var value = (bool)currentValue.Value;
                                if (value)
                                    iconList.Add(info);
                            }
                        }
                    }
                }
            }
            return StatusToIconMapper.MapFromProcessValues(iconList);
        }

        #endregion Status

        private string GetSequenceStep(ProjectItemCollectionSequence sequence)
        {
            if (!_lookUpTableSeqProcessValueInfos.ContainsKey(sequence.SequenceInfo.Id))
            {
                return "No step available";
            }

            var stepDef = _lookUpTableSeqProcessValueInfos[sequence.SequenceInfo.Id].Status.StepCount;

            if (!_lookUpTableSeqOverviewValues.ContainsKey(stepDef.Id))
            {
                return "No step available";
            }
            if (_lookUpTableSeqOverviewValues[stepDef.Id].Value == null)
            {
                return "No connection";
            }
            var stepCount = (Int16)_lookUpTableSeqOverviewValues[stepDef.Id].Value;
            if (stepCount != 0 && sequence.StepCollection.Steps != null && sequence.StepCollection.Steps.Count() > 0)
                return $"{stepCount} - {GetStepName(sequence, stepCount)}";
            return "No step available";
        }

        private string GetStepName(ProjectItemCollectionSequence sequence, Int16 stepCount)
        {
            foreach (var stepValuePair in sequence.SequenceInfo.StepOrder.ToDictionary())
            {
                if (stepCount == stepValuePair.Value)
                {
                    var matchingStep = sequence.StepCollection.Steps.
                        FirstOrDefault(step => step.Id.Guid.Equals(stepValuePair.Key.Guid));

                    if (matchingStep != null)
                    {
                        var hmiText = matchingStep.HmiDisplayText.Trim();
                        if (!string.IsNullOrEmpty(hmiText))
                        {
                            return hmiText;
                        }

                        return matchingStep.Name;
                    }
                    else
                        return "No step available";
                }
            }
            return "No step available";
        }

        #endregion Handle ProcessValues

        #region ComponentHandling

        public event EventHandler<ComponentEventArgs> ComponentChangeEvent;

        public List<IProcessValueInfo> GetValueInfos()
        {
            if (_sequences == null || _projectInformationService.CurrentSequence.SequenceInfo == null)
            {
                return new();
            }

            var values = _processValueInfoService
              .CreateSeqOverviewRegistration(_sequences.Select(s => s.SequenceInfo).ToList()).ValueInfos;

            _lookUpTableSeqProcessValueInfos = _processValueInfoService
               .GetProcessValueInfoLookUpTableOverview(_sequences.Select(s => s.SequenceInfo).ToList());

            _lookUpTableSeqOverview = new ConcurrentDictionary<SequenceId, List<IProcessValueInfo>>
                (_processValueInfoService.GetLookUpTableForSeqOverview(_sequences.Select(s => s.SequenceInfo).ToList()));

            _lookUpTableSeqStatus = _processValueInfoService
                .GetLookUpTableForSeqStatus(_projectInformationService.Sequences.ToList());

            return new();
        }

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

            UpdateSequencesIconState(updatedValues);

            foreach (var valueInfos in _lookUpTableSeqOverview.Values)
            {
                foreach (var valueInfo in valueInfos)
                {
                    if (updatedValues.ContainsKey(valueInfo.Id))
                    {
                        var value = updatedValues[valueInfo.Id];
                        _lookUpTableSeqOverviewValues[value.ValueInfo.Id] = value;
                        //UpdateValue(updatedValues[valueInfo.Id]);
                    }
                }
            }
        }

        #endregion ComponentHandling

        public async ValueTask DisposeAsync()
        {
        }
    }
}