// Copyright © Selmo Technology GmbH. All Rights Reserved

using Microsoft.AspNetCore.Components;
using Novus.Connectivity.Common;
using SelmoStudio.Hmi.Server.SelmoHmi.Parameter.Model.Dto;

namespace SelmoStudio.Hmi.Server.ProcessValue.Validator
{
    public static class ProcessValueValidator
    {
        [Inject]
        private static ILogger _logger { get; set; } = StaticLogger();

        private static ILogger StaticLogger()
        {
            var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
            return loggerFactory.CreateLogger(typeof(ProcessValueValidator));
        }

        public static bool CheckDataTypeLimits(Type datatype, object value)
        {
            if (datatype == typeof(string))
            {
                if (value.ToString().Length > 80)
                    return false;

                return true;
            }

            if (datatype == typeof(bool))
            {
                return true;
            }

            if (!double.TryParse(value.ToString(), out var parsedValue)) return false;

            if (datatype == typeof(Byte))
            {
                return IsInRange(parsedValue, Byte.MinValue, Byte.MaxValue);
            }
            if (datatype == typeof(SByte))
            {
                return IsInRange(parsedValue, SByte.MinValue, SByte.MaxValue);
            }
            if (datatype == typeof(Int16))
            {
                return IsInRange(parsedValue, Int16.MinValue, Int16.MaxValue);
            }
            if (datatype == typeof(UInt16))
            {
                return IsInRange(parsedValue, UInt16.MinValue, UInt16.MaxValue);
            }
            if (datatype == typeof(Int32))
            {
                return IsInRange(parsedValue, Int32.MinValue, Int32.MaxValue);
            }
            if (datatype == typeof(UInt32))
            {
                return IsInRange(parsedValue, UInt32.MinValue, UInt32.MaxValue);
            }
            if (datatype == typeof(Int64))
            {
                return IsInRange(parsedValue, Int64.MinValue, Int64.MaxValue);
            }
            if (datatype == typeof(UInt64))
            {
                return IsInRange(parsedValue, UInt64.MinValue, UInt64.MaxValue);
            }
            if (datatype == typeof(Single))
            {
                return IsInRange(parsedValue, Single.MinValue, Single.MaxValue);
            }
            if (datatype == typeof(Double))
            {
                return IsInRange(parsedValue, Double.MinValue, Double.MaxValue);
            }

            return false;
        }

        private static bool IsInRange(double parsedValue, double minValue, double maxValue)
        {
            return parsedValue >= minValue && parsedValue <= maxValue;
        }

        public static bool Validate(ParameterDto param, IProcessValueInfo info, object value)
        {
            if (!CheckDataTypeLimits(info.DataType, value)) return false;

            if (info.DataType == typeof(string))
            {
                if (value.ToString().Length > 80)
                    return false;

                return true;
            }
            if (info.DataType == typeof(bool))
            {
                return ValidateBool(param, value);
            }
            if (info.DataType == typeof(Int16))
            {
                return ValidateInt16(param, value);
            }

            if (info.DataType == typeof(Int32))
            {
                return ValidateInt32(param, value);
            }

            if (info.DataType == typeof(double))
            {
                return ValidateDouble(param, value);
            }

            if (info.DataType == typeof(float))
            {
                return ValidateFloat(param, value);
            }
            return true;
        }

        private static bool ValidateBool(ParameterDto param, object value)
        {
            try
            {
                if (!bool.TryParse(value.ToString(), out var parsed))
                {
                    _logger.LogError($"Input for {param.Name} wrong. ({value})");
                    return false;
                }

                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError($"Caught Exception: {ex.Message} when validating Process Value");
                return false;
            }
            return true;
        }

        private static bool ValidateFloat(ParameterDto param, object value)
        {
            try
            {
                float fValue = float.Parse(value.ToString());
                if (fValue > param.LimitMax || fValue < param.LimitMin)
                {
                    _logger.LogError($"Input for {param.Name} wrong. ({value})");
                    return false;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"Caught Exception: {ex.Message} when validating Process Value");
                return false;
            }
            return true;
        }

        private static bool ValidateDouble(ParameterDto param, object value)
        {
            try
            {
                double dValue = double.Parse(value.ToString());
                if (dValue > param.LimitMax || dValue < param.LimitMin)
                {
                    _logger.LogError($"Input for {param.Name} wrong. ({value})");
                    return false;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"Caught Exception: {ex.Message} when validating value");
                return false;
            }
            return true;
        }

        private static bool ValidateInt32(ParameterDto param, object value)
        {
            try
            {
                Int32 iValue = Int32.Parse(value.ToString());
                if (iValue > param.LimitMax || iValue < param.LimitMin)
                {
                    _logger.LogError($"Error in {nameof(ValidateInt32)}() Max/Min ({value})");
                    return false;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"Caught Exception: {ex.Message} when validating value");
                return false;
            }
            return true;
        }

        private static bool ValidateInt16(ParameterDto param, object value)
        {
            try
            {
                Int16 iValue = Int16.Parse(value.ToString());
                if (iValue > param.LimitMax || iValue < param.LimitMin)
                {
                    _logger.LogError($"Error in {nameof(ValidateInt16)}() Max/Min ({value})");
                    return false;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"Caught Exception: {ex.Message} when validating value");
                return false;
            }
            return true;
        }
    }
}