using Aitex.Core.Common.DeviceData.IoDevice;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using System;
using System.Xml;

namespace Aitex.Core.RT.Device.Devices
{
    public class IoSCR : BaseDevice, IDevice
    {
        #region Variables
        private float _resLimitMax;

        private readonly bool _isFloatAioType = true;

        private readonly AIAccessor _aiVoltage;
        private readonly AIAccessor _aiArms;
        private readonly AIAccessor _aiPower;
        private readonly DIAccessor _diStatus;
        private DIAccessor _diAlarm;

        private DIAccessor _diPSUCommunicationError;//PSU总的报警
        private DIAccessor _diSCRCommunicationError;//SCR总的报警    二者任意报警，关闭所有加热
        private readonly R_TRIG _psuCommunicationError = new();

        private readonly DOAccessor _doStatus;
        private readonly DOAccessor _doReset;

        private readonly DeviceTimer _timResetPulse = new();

        private readonly R_TRIG _trigResOutOfRange = new();
        private readonly DeviceTimer _timResOutOfRange = new();

        private readonly IoPsuData _deviceData = new();

        #endregion

        #region Constructors

        public IoSCR(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule)
        {
            _aiVoltage = ParseAiNode("aiVoltage", node, ioModule);
            _aiArms = ParseAiNode("aiArms", node, ioModule);
            _aiPower = ParseAiNode("aiPower", node, ioModule);
            _diStatus = ParseDiNode("diStatus", node, ioModule);

            _doReset = ParseDoNode("doReset", node, ioModule);
            _doStatus = ParseDoNode("doStatus", node, ioModule);
            _diAlarm = ParseDiNode("diAlarm", node, ioModule);

            _diPSUCommunicationError = ParseDiNode("diPSUCommunicationError", node, ioModule);
            _diSCRCommunicationError = ParseDiNode("diSCRCommunicationError", node, ioModule);

            _isFloatAioType = !string.IsNullOrEmpty(node.GetAttribute("aioType")) && (node.GetAttribute("aioType") == "float");
        }

        #endregion

        #region Properties

        public float VoltageFeedBack => _aiVoltage == null ? 0 : (_isFloatAioType ? _aiVoltage.Value : _aiVoltage.Value);

        public float ArmsFeedBack => _aiArms == null ? 0 : (_isFloatAioType ? _aiArms.Value : _aiArms.Value);

        public float ResistanceLimitMax => _resLimitMax;

        public float Resistance => ArmsFeedBack == 0 ? 0 : VoltageFeedBack / ArmsFeedBack;

        public bool IsResistanceOutOfRange => IsResistanceTooHigh;

        public bool IsResistanceTooHigh { get; private set; }

        public float PowerFeedBack => _aiPower == null ? 0 : (_isFloatAioType ? _aiPower.Value : _aiPower.Value);

        public bool StatusFeedBack => _diStatus == null ? false : _diStatus.Value;

        private IoPsuData DeviceData
        {
            get
            {
                _deviceData.IsAlarm = false;
                _deviceData.OutputStatusFeedBack = StatusFeedBack;
                _deviceData.OutputArmsFeedBack = ArmsFeedBack;
                _deviceData.OutputPowerFeedBack = PowerFeedBack;
                _deviceData.OutputVoltageFeedback = VoltageFeedBack;
                _deviceData.ResistanceLimitMax = ResistanceLimitMax;
                _deviceData.Resistance = Resistance;
                _deviceData.IsResistanceOutOfRange = IsResistanceOutOfRange;
                _deviceData.IsResistanceTooHigh = IsResistanceTooHigh;
                return _deviceData;
            }
        }


        #endregion

        #region Methods

        public bool Initialize()
        {
            DATA.Subscribe($"{Module}.{Name}.VoltageFeedBack", () => VoltageFeedBack);
            DATA.Subscribe($"{Module}.{Name}.ArmsFeedBack", () => ArmsFeedBack);
            DATA.Subscribe($"{Module}.{Name}.Resistance", () => Resistance);
            DATA.Subscribe($"{Module}.{Name}.PowerFeedBack", () => PowerFeedBack);
            DATA.Subscribe($"{Module}.{Name}.StatusFeedBack", () => StatusFeedBack);
            DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData);


            OP.Subscribe($"{Module}.{Name}.SetEnable", (function, args) =>
            {
                var isTrue = Convert.ToBoolean(args[0]);
                SetEnable(isTrue, out _);
                return true;
            });
            OP.Subscribe($"{Module}.{Name}.SetReset", (function, args) =>
            {
                var isTrue = Convert.ToBoolean(args[0]);
                SetReset(isTrue, out _);
                return true;
            });

            return true;
        }


        public bool SetEnable(bool setValue, out string reason)
        {
            if (!_doStatus.Check(setValue, out reason))
                return false;
            if (!_doStatus.SetValue(setValue, out reason))
            {
                return false;
            }

            return true;
        }

        public bool SetReset(bool setValue, out string reason)
        {
            if (!_doReset.Check(setValue, out reason))
                return false;
            if (!_doReset.SetValue(setValue, out reason))
            {
                return false;
            }

            _timResetPulse.Start(1000);

            return true;
        }

        public bool CheckSCREnable()
        {
            return _doStatus.Value;
        }

        public void Terminate()
        {
        }

        protected override void HandleMonitor()
        {
            try
            {
                MonitorAlarm();

                MonitorCheckPSUCommunicationError();

                if (_timResetPulse.IsTimeout())
                {
                    _timResetPulse.Stop();
                    if (_doReset.Value)
                        _doReset.Value = false;

                    ResetResistanceMonitorResult();
                }

            }
            catch (Exception ex)
            {
                LOG.Write(ex);
            }
        }

        private void MonitorCheckPSUCommunicationError()
        {
            if ((_diPSUCommunicationError?.Value ?? false) || (_diSCRCommunicationError?.Value ?? false))
            {
                _psuCommunicationError.CLK = true;
                if (_psuCommunicationError.Q)
                {
                    EV.PostWarningLog(Module, $"PSU or SCR is communication error! Set {Name} heat enable");
                    SetEnable(false, out _);
                }
            }
            else
            {
                _psuCommunicationError.RST = true;
            }
        }


        public void Reset()
        {
            ResetResistanceMonitorResult();
        }

        /// <summary>
        /// 复位加热器电阻监测结果。
        /// </summary>
        private void ResetResistanceMonitorResult()
        {
            IsResistanceTooHigh = false;
            _trigResOutOfRange.RST = true;
            _timResOutOfRange.Stop();
        }

        private void MonitorAlarm()
        {
            //检查电阻值是否在合理范围
            _resLimitMax = (float)SC.GetValue<double>($"PM.{Module}.Heater.{Name}ResistanceMax");
            var timeOut = SC.GetValue<int>($"PM.{Module}.Heater.ResistanceMonitorHysteresis");

            if (Resistance > _resLimitMax && _timResOutOfRange.IsIdle())
            {
                _timResOutOfRange.Start(timeOut * 1000);
            }

            if (Resistance <= _resLimitMax)
            {
                IsResistanceTooHigh = false;
                _timResOutOfRange.Stop();
            }

            _trigResOutOfRange.CLK = _timResOutOfRange.IsTimeout();
            if (_trigResOutOfRange.Q)
            {
                IsResistanceTooHigh = true;
                EV.PostWarningLog(Module, $"{Name} Current resistance {Resistance}ohm exceeds the high limit {_resLimitMax}ohm.");
            }
        }
      

        #endregion
    }
}
