// Copyright © Selmo Technology GmbH. All Rights Reserved

using Novus.Connectivity.Common;
using Novus.Connectivity.Service;
using Novus.Shared.Types.Result;
using Opc.Ua;

// Copyright © Selmo Technology GmbH. All Rights Reserved

namespace SelmoStudio.Hmi.Server.Diagnostic
{
    public class AppDiagnosticService : IAppDiagnosticService
    {
        private readonly ILogger<AppDiagnosticService> _logger;

        public AppDiagnosticService(ILogger<AppDiagnosticService> logger)
        {
            _logger = logger;
        }

        private DiagnosticSettings _settings;
        private bool _isInit = false;
        private ValueInfo _oldValues;

        void IAppDiagnosticService.Init()
        {
            if (_isInit) { return; }

            DiagnosticSettingHelper.CreateIfNotExists();

            _settings = DiagnosticSettingHelper.GetDiagnosticSettings();
            _isInit = true;
        }

        public async Task AnalyzeReadAll(IRegisteredValueConnectionService regValueService)
        {
            if (!_settings.LogValueChangeFromDevice)
                return;

            var allValuesOpRes = await regValueService.GetAllValues();

            AnalyzeValueChanges(allValuesOpRes);
        }

        public async Task AnalyzeRead(IRegisteredValueConnectionService regValueService, ValuesConnectionRegistrationId id)
        {
            if (!_settings.LogValueChangeFromDevice)
                return;

            var valuesOpRes = await regValueService.GetValues(id);

            AnalyzeValueChanges(valuesOpRes);
        }

        private void AnalyzeValueChanges(OperationResult<ValueInfo> valuesOpRes)
        {
            List<string> changes = new List<string>();
            string lastReaded = string.Empty;

            try
            {
                var currentValues = valuesOpRes.Value;
                if (_oldValues == null)
                {
                    _oldValues = currentValues;
                    return;
                }

                foreach (var value in currentValues.ProcessValues)
                {
                    if (!_oldValues.ProcessValues.ContainsKey(value.Value.ValueInfo.Id))
                    {
                        continue;
                    }
                    lastReaded = value.Value.ValueInfo.Address.FullPath;
                    var old = _oldValues.ProcessValues[value.Value.ValueInfo.Id];

                    if (value.Value.Value == null)
                    {
                        _logger.LogError($"!!!!! ERROR !!!! {value.Value.ValueInfo.Address} == null");
                        continue;
                    }

                    if (!value.Value.Value.ToString().Equals(old.Value.ToString()))
                    {
                        changes.Add($"Value Changed => {value.Value.ValueInfo.Address.FullPath} => old({old.Value})/new({value.Value.Value})");
                    }
                }
                _oldValues = currentValues;
            }
            catch (Exception ex)
            {
                _logger.LogError($"----------- Error in Analyze Value Changes  ------------------------", ex);
                _logger.LogError($"last readed = {lastReaded}");
            }

            if (changes.Count > 0)
            {
                _logger.LogInformation($"----------- Analyze Value Changes START ------------------------");
                foreach (var change in changes)
                {
                    _logger.LogInformation($"{change}");
                }
                _logger.LogInformation($"----------- Analyze Value Changes End ------------------------");
                _logger.LogWarning($"!!!!!! DON'T forget to turn OFF Analysis after USAGE !!!!!!");
            }
        }

        public async Task AnalyzeWrite(IRegisteredValueConnectionService regValueService, IProcessValue value)
        {
            if (!_settings.LogValueWriteToDevice)
                return;

            if (value.ValueInfo != null)
            {
                var allProcessValues = await regValueService.GetAllValues();

                if (allProcessValues.Value.ProcessValues.ContainsKey(value.ValueInfo.Id))
                {
                    var foundValue = allProcessValues.Value.ProcessValues[value.ValueInfo.Id].Value;
                    if (foundValue == null)
                    {
                        _logger.LogError($"Error !!!!. Cannot access value {value.ValueInfo.Address.FullPath}");
                    }
                }
                else
                {
                    _logger.LogError($"Error !!!!. Cannot access value {value.ValueInfo.Address.FullPath}");
                }

                _logger.LogInformation($"{nameof(WriteValue)} => {value.ValueInfo.Address.FullPath}[{value.ValueInfo.DataType}]={value.Value}");
            }
        }
    }
}