// 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.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.WellKnownTypes;

namespace SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Components
{
    public partial class SequenceControlComponent : IBaseProcessValueComponent, IAsyncDisposable
    {
        [Inject]
        private ILogger<SequenceContentComponent> _logger { get; set; }

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

        [Inject]
        private IProjectInformationService _projectInformationService { get; set; }

        private ProcessValuesSequence _sequenceValueInfos;

        private Dictionary<ProcessValueId, bool> _boolProcessValues = new();

        private WellKnownContentFlexDirection contentFlexDirection = WellKnownContentFlexDirection.Column;

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

        [Parameter]
        public SequenceId SequenceId { get; set; }

        #region Init/Lifecycle

        protected override void OnInitialized()
        {
            _projectInformationService.SequenceUpdated += SequenceUpdated;

            _logger.LogInformation($"Init {nameof(SequenceControlComponent)}");
        }

        private bool _isRendered;

        public bool IsRendered
        {
            get
            {
                return _isRendered;
            }
        }

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

        #endregion Init/Lifecycle

        #region Handle ProcessValue Get/Set

        private void SequenceUpdated()
        {
            _logger.LogInformation("Sequence Updated in Step Control.");
            ResetBoolValues();
        }

        private void ResetBoolValues()
        {
            if (_sequenceValueInfos == null)
                return;

            _boolProcessValues = new()
            {
               { _sequenceValueInfos.Status.GhostModeInput.Id, false },
               { _sequenceValueInfos.TriggerSingleStepOn.Id, false }
            };
        }

        private void CheckValue(IProcessValue value)
        {
            if (_boolProcessValues.ContainsKey(value.ValueInfo.Id))
            {
                if (value.Value == null || value.Value == null)
                    return;
                _boolProcessValues[value.ValueInfo.Id] = (bool)value.Value;
            }
        }

        #endregion Handle ProcessValue Get/Set

        private bool GetGhostModeValue()
        {
            if (_sequenceValueInfos == null)
                return false;

            return _boolProcessValues[_sequenceValueInfos.Status.GhostModeInput.Id];
        }

        private bool GetSingleStepOnValue()
        {
            return _boolProcessValues[_sequenceValueInfos.TriggerSingleStepOn.Id];
        }

        #region ComponentHandling

        public event EventHandler<ComponentEventArgs> ComponentChangeEvent;

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

            var values = _processValueInfoService.CreateSequenceRegistrationWithoutStepCounter(
                _projectInformationService.CurrentSequence.SequenceInfo.Id).ValueInfos;
            _sequenceValueInfos = _processValueInfoService.GetProcessValueInfo(
                _projectInformationService.CurrentSequence.SequenceInfo.Id);
            ResetBoolValues();
            var newList = values[5..7].ToList();
            newList.AddRange(values[1..3].ToList());
            return newList;
        }

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

            foreach (var value in _boolProcessValues)
            {
                if (updatedValues.ContainsKey(value.Key))
                {
                    CheckValue(updatedValues[value.Key]);
                }
            }
        }

        private ProcessValueHandleInfo? GetValueHandleInfo(Guid id, bool val)
        {
            if (_sequenceValueInfos.Status.GhostModeInput.Id.Guid.Equals(id))
                return new ProcessValueHandleInfo()
                {
                    ProcessValueHandle = ProcessValueHandle.SetValue,
                    ProcessValueInfo = _sequenceValueInfos.Status.GhostModeInput,
                    Value = !GetGhostModeValue()
                };

            if (_sequenceValueInfos.TriggerSingleStepOn.Id.Guid.Equals(id))
                return new ProcessValueHandleInfo()
                {
                    ProcessValueHandle = ProcessValueHandle.SetValue,
                    ProcessValueInfo = _sequenceValueInfos.TriggerSingleStepOn,
                    Value = !GetSingleStepOnValue()
                };

            IProcessValueInfo info = null;

            if (_sequenceValueInfos.TriggerStepDecrement.Id.Guid.Equals(id))
                info = _sequenceValueInfos.TriggerStepDecrement;
            if (_sequenceValueInfos.TriggerStepIncrement.Id.Guid.Equals(id))
                info = _sequenceValueInfos.TriggerStepIncrement;
            if (_sequenceValueInfos.TriggerStepNextValid.Id.Guid.Equals(id))
                info = _sequenceValueInfos.TriggerStepNextValid;
            if (_sequenceValueInfos.TriggerStepSingle.Id.Guid.Equals(id))
                info = _sequenceValueInfos.TriggerStepSingle;
            if (_sequenceValueInfos.TriggerStepReset.Id.Guid.Equals(id))
                info = _sequenceValueInfos.TriggerStepReset;

            if (info != null)
            {
                return new ProcessValueHandleInfo()
                {
                    ProcessValueHandle = ProcessValueHandle.SetValue,
                    ProcessValueInfo = info,
                    Value = val
                };
            }
            return null;
        }

        public void TriggerComponentChangeEvent(ButtonEventArgs e, Guid id, bool val = false)
        {
            if (e == null)
                return;
            var processValueHandle = GetValueHandleInfo(id, val);
            if (processValueHandle == null)
                return;

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

        #endregion ComponentHandling

        public async ValueTask DisposeAsync()
        {
            _projectInformationService.SequenceUpdated -= SequenceUpdated;
        }
    }
}