// Copyright © Selmo Technology GmbH. All Rights Reserved

using Microsoft.AspNetCore.Components;
using Novus.Connectivity.Common;
using Novus.Connectivity.Service;
using Novus.Shared.Types.Extensions;
using SelmoStudio.Hmi.Common.SelmoProject;
using SelmoStudio.Hmi.Common.SelmoProject.ProcessValueDefinition;
using SelmoStudio.Hmi.Server.ProcessValue.Services;
using SelmoStudio.Hmi.Server.SelmoHmi.Helpers;
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.Component.Ids;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.Service;
using SelmoStudio.Hmi.Server.Shared.Components.BaseComponents;
using SelmoStudio.Hmi.Server.Shared.Service;
using WpfGridLayout.Blazor;

namespace SelmoStudio.Hmi.Server.UserDefined
{
    public abstract class ComponentPageBase : Microsoft.AspNetCore.Components.ComponentBase, IDisposable
    {
        protected Dictionary<ComponentId, VariableDefinition> _defaultElementValues = new();
        protected HmiSettings _hmiSettings = new();

        protected SelmoHmiValueHandler _selmoHmiValueHandler;

        [Inject]
        protected IProjectService _projectService { get; set; }

        [Inject]
        protected IProcessValuePollingService _valuePollingService { get; set; }

        [Inject]
        protected IRegistrationService _registrationService { get; set; }

        //[Inject]
        //protected IJSRuntime _jsRuntime { get; set; }

        //protected IJSObjectReference _resizeCallbackRef;

        protected async Task ButtonMouseDown(ButtonEventArgs e)
        {
            if (e == null)
                return;

            var processValue = GetProcessValueInfo(e.Id);

            if (processValue == null)
                return;

            var handle = new ProcessValueHandleInfo()
            {
                ProcessValueHandle = ProcessValueHandle.SetValue,
                ProcessValueInfo = processValue,
                Value = true
            };

            var componentEvent = ComponentEventArgs.Create(e, handle);
            await _selmoHmiValueHandler.HandleEvent(componentEvent);
        }

        protected IProcessValueInfo? GetProcessValueInfo(ComponentId id)
        {
            if (!_valuesToRegister.ContainsKey(id))
                return null;

            return _valuesToRegister[id];
        }

        private void OnEventTriggered(object? sender, ComponentEventArgs e)
        {
            _selmoHmiValueHandler.HandleEvent(e);
        }

        protected void IntervalElapsed(object sender, EventArgs e)
        {
            Task.Run(async () =>
            {
                var valuesToRegister = GetValueInfos();
                var regId = HandleRegistration(valuesToRegister);

                if (regId.Guid.IsEmpty() || !_valuePollingService.IsReady())
                {
                    return;
                }

                var valueOperation = await _valuePollingService.GetValues(regId);

                if (valueOperation.Issues.Any())
                {
                    return;
                }

                var processValues = valueOperation.Value.ProcessValues;

                Update(processValues);
            });
        }

        #region Process Value Registration

        private Dictionary<ProcessValueId, IProcessValueInfo> _registeredProcessValues = new();
        private ValuesConnectionRegistrationId _currentRegistration;

        private ValuesConnectionRegistrationId HandleRegistration(List<IProcessValueInfo> valuesToRegister)
        {
            if (AnyValueToRegister(valuesToRegister))
            {
                _registeredProcessValues = valuesToRegister.ToDictionary(item => item.Id);
                ValuesConnectionRegistration reg = ValuesConnectionRegistration.Create(valuesToRegister.ToArray());

                _valuePollingService.RegisterValues(reg);
                _currentRegistration = reg.Id;
            }
            return _currentRegistration;
        }

        private bool AnyValueToRegister(List<IProcessValueInfo> valuesToRegister)
        {
            foreach (var info in valuesToRegister)
            {
                if (!_registeredProcessValues.ContainsKey(info.Id))
                    return true;
            }

            return false;
        }

        #endregion Process Value Registration

        #region Value Info

        private Dictionary<ComponentId, IProcessValueInfo> _valuesToRegister = new();

        public List<IProcessValueInfo> GetValueInfos()
        {
            if (_valuesToRegister == null || _valuesToRegister.Count == 0)
            {
                _valuesToRegister = GetPageProcessValues(_defaultElementValues, _hmiSettings);
                return _valuesToRegister.Values.ToList();
            }
            return new();
        }

        public static Dictionary<ComponentId, IProcessValueInfo> GetPageProcessValues(
            Dictionary<ComponentId, VariableDefinition> defaultElementValues, HmiSettings hmiSettings)
        {
            Dictionary<ComponentId, IProcessValueInfo> values = new();
            foreach (var elementValue in defaultElementValues)
            {
                var pv = InternalProcessValueInfoHelper.CreateValueInfo(elementValue.Value, hmiSettings);
                values.Add(elementValue.Key, pv);
            }
            return values;
        }

        #endregion Value Info

        #region Value Update

        protected IDictionary<ProcessValueId, IProcessValue> _updatedValues = new Dictionary<ProcessValueId, IProcessValue>();

        public void Update(IDictionary<ProcessValueId, IProcessValue> updatedValues)
        {
            _updatedValues = updatedValues;
            RefreshValues(_updatedValues);
        }

        public abstract void RefreshValues(IDictionary<ProcessValueId, IProcessValue> updatedValues);

        #endregion Value Update

        protected async Task ToggleProcessValue(ButtonEventArgs e)
        {
            if (e == null)
                return;

            var value = GetValue(e.Id);
            if (value?.Value is not bool currentValue)
                return;

            await SetProcessValue(e.ToEventInfo(), value.ValueInfo, !currentValue);
        }

        protected async Task SetProcessValue(ComponentEventInfo e, object value)
        {
            if (e == null)
                return;

            var pvInfo = GetValue(e.ComponentId);
            if (pvInfo == null)
                return;

            await SetProcessValue(e, pvInfo.ValueInfo, value);
        }

        protected async Task SetProcessValue(TextBoxEventArgs e)
        {
            if (e == null)
                return;

            var pvInfo = GetValue(e.Id);
            if (pvInfo == null)
                return;

            if (pvInfo.ValueInfo != null && !string.IsNullOrEmpty(e.Value))
            {
                //if (!ProcessValueValidator.Validate(parameter, valueInfo, value))
                //{
                //    parameter.LoadedValue = oldValue;
                //    return;
                //}

                //if (pvInfo.ValueInfo.DataType.PlcType == Common.SelmoProject.Types.HmiPlcType.TIME)
                //{
                //    value = ConvertToTimerValue(value, parameter.Unit);
                //}

                await SetProcessValue(e.ToEventInfo(), pvInfo.ValueInfo, e.Value);
            }
        }

        protected async Task SetProcessValue(ComponentEventInfo e, IProcessValueInfo info, object value)
        {
            var handle = new ProcessValueHandleInfo()
            {
                ProcessValueHandle = ProcessValueHandle.SetValue,
                ProcessValueInfo = info,
                Value = value
            };

            var componentEvent = ComponentEventArgs.Create(e, handle);
            await _selmoHmiValueHandler.HandleEvent(componentEvent);
        }

        public string GetButtonStyle(ButtonComponent component)
        {
            if (component == null)
                return $"background-color: {HtmlStyleHelper.GetToggleButtonBackgroundColor(false)};";

            var processValue = GetProcessValueInfo(component.ComponentId);

            if (processValue == null)
                return $"background-color: {HtmlStyleHelper.GetToggleButtonBackgroundColor(false)};";

            if (bool.TryParse(_updatedValues[processValue.Id].Value.ToString(), out bool currentValue) && currentValue)
            {
                return $"background-color:  {HtmlStyleHelper.GetActiveInOutZoneButtonBackgroundColor()};";
            }

            return $"background-color: {HtmlStyleHelper.GetToggleButtonBackgroundColor(false)};";
        }

        public string GetButtonStyle()
        {
            return $"background-color: {HtmlStyleHelper.GetToggleButtonBackgroundColor(false)};";
        }

        protected IProcessValue? GetValue(ComponentId componentId)
        {
            var processValue = GetProcessValueInfo(componentId);

            if (processValue == null)
                return null;

            var value = _updatedValues[processValue.Id];

            return value;
        }

        void IDisposable.Dispose()
        {
            _valuePollingService.OnIntervalElapsed += IntervalElapsed;
        }
    }
}