using MainShell.Hardware;
using MainShell.Log;
using MainShell.Models;
using MwFramework.Device.Delta;
using Stylet;
using System;
using System.Globalization;

namespace MainShell.DeviceMaintance.ViewModel
{
    public class IoTestViewModel : BaseScreen
    {
        public class DeltaBitTestState : PropertyChangedBase
        {
            private int _cardNo;
            public int CardNo
            {
                get { return _cardNo; }
                set { SetAndNotify(ref _cardNo, value); }
            }

            private int _node;
            public int Node
            {
                get { return _node; }
                set { SetAndNotify(ref _node, value); }
            }

            private int _slot;
            public int Slot
            {
                get { return _slot; }
                set { SetAndNotify(ref _slot, value); }
            }

            private int _index;
            public int Index
            {
                get { return _index; }
                set { SetAndNotify(ref _index, value); }
            }

            private int _subIndex;
            public int SubIndex
            {
                get { return _subIndex; }
                set { SetAndNotify(ref _subIndex, value); }
            }

            private int _bitNo;
            public int BitNo
            {
                get { return _bitNo; }
                set { SetAndNotify(ref _bitNo, value); }
            }

            private int _ioType = 1;
            public int IoType
            {
                get { return _ioType; }
                set { SetAndNotify(ref _ioType, value); }
            }

            private int _readIoType = 1;
            public int ReadIoType
            {
                get { return _readIoType; }
                set { SetAndNotify(ref _readIoType, value); }
            }

            private bool _writeValue;
            public bool WriteValue
            {
                get { return _writeValue; }
                set { SetAndNotify(ref _writeValue, value); }
            }

            private bool _readValue;
            public bool ReadValue
            {
                get { return _readValue; }
                set { SetAndNotify(ref _readValue, value); }
            }

            private ushort _returnCode;
            public ushort ReturnCode
            {
                get { return _returnCode; }
                set { SetAndNotify(ref _returnCode, value); }
            }

            private string _resultMessage = string.Empty;
            public string ResultMessage
            {
                get { return _resultMessage; }
                set { SetAndNotify(ref _resultMessage, value); }
            }
        }

        public class DeltaDaTestState : PropertyChangedBase
        {
            private int _cardNo;
            public int CardNo
            {
                get { return _cardNo; }
                set { SetAndNotify(ref _cardNo, value); }
            }

            private int _node;
            public int Node
            {
                get { return _node; }
                set { SetAndNotify(ref _node, value); }
            }

            private int _slot;
            public int Slot
            {
                get { return _slot; }
                set { SetAndNotify(ref _slot, value); }
            }

            private int _index;
            public int Index
            {
                get { return _index; }
                set { SetAndNotify(ref _index, value); }
            }

            private int _subIndex;
            public int SubIndex
            {
                get { return _subIndex; }
                set { SetAndNotify(ref _subIndex, value); }
            }

            private int _byteSize = 2;
            public int ByteSize
            {
                get { return _byteSize; }
                set { SetAndNotify(ref _byteSize, value); }
            }

            private bool _signed = true;
            public bool Signed
            {
                get { return _signed; }
                set { SetAndNotify(ref _signed, value); }
            }

            private int _ioType = 1;
            public int IoType
            {
                get { return _ioType; }
                set { SetAndNotify(ref _ioType, value); }
            }

            private int _writeRawValue;
            public int WriteRawValue
            {
                get { return _writeRawValue; }
                set { SetAndNotify(ref _writeRawValue, value); }
            }

            private int _readRawValue;
            public int ReadRawValue
            {
                get { return _readRawValue; }
                set { SetAndNotify(ref _readRawValue, value); }
            }

            private ushort _returnCode;
            public ushort ReturnCode
            {
                get { return _returnCode; }
                set { SetAndNotify(ref _returnCode, value); }
            }

            private string _resultMessage = string.Empty;
            public string ResultMessage
            {
                get { return _resultMessage; }
                set { SetAndNotify(ref _resultMessage, value); }
            }
        }

        private readonly HardwareManager _hardwareManager;

        private string _cardStatusText;
        public string CardStatusText
        {
            get { return _cardStatusText; }
            set { SetAndNotify(ref _cardStatusText, value); }
        }

        public DeltaBitTestState BitState { get; private set; }

        public DeltaDaTestState DaState { get; private set; }

        public IoTestViewModel(HardwareManager hardwareManager)
        {
            if (hardwareManager == null)
            {
                throw new ArgumentNullException(nameof(hardwareManager));
            }

            _hardwareManager = hardwareManager;
            BitState = BuildBitState();
            DaState = BuildDaState();
            RefreshCardStatus();
        }

        protected override void OnViewLoaded()
        {
            base.OnViewLoaded();
            RefreshCardStatus();
        }

        public void RefreshCardStatus()
        {
            IDeltaIoExtend deltaIoExtend;
            bool available = _hardwareManager.TryGetDeltaIoExtend(out deltaIoExtend);
            CardStatusText = available ? $"Delta卡已连接：{_hardwareManager.TdCard.GetType().FullName}" : "Delta卡未初始化或未实现 IDeltaIoExtend";
        }

        public void ReadBit()
        {
            try
            {
                IDeltaIoExtend deltaIoExtend;
                if (!TryGetDeltaIoExtend(out deltaIoExtend))
                {
                    return;
                }

                ushort cardNo;
                ushort node;
                ushort slot;
                ushort index;
                ushort subIndex;
                byte bitNo;
                ushort ioType;
                if (!TryGetBitReadParameters(out cardNo, out node, out slot, out index, out subIndex, out bitNo, out ioType))
                {
                    return;
                }

                bool value;
                ushort result = deltaIoExtend.ReadBit(cardNo, node, slot, index, subIndex, bitNo, out value, ioType);
                BitState.ReadValue = value;
                BitState.ReturnCode = result;
                BitState.ResultMessage = $"ReadBit 返回码：{result}，结果：{value}";
            }
            catch (Exception ex)
            {
                HandleException(ex, BitState, "ReadBit 执行异常");
            }
        }

        public void WriteBit()
        {
            try
            {
                IDeltaIoExtend deltaIoExtend;
                if (!TryGetDeltaIoExtend(out deltaIoExtend))
                {
                    return;
                }

                ushort cardNo;
                ushort node;
                ushort slot;
                ushort index;
                ushort subIndex;
                byte bitNo;
                ushort readIoType;
                if (!TryGetBitWriteParameters(out cardNo, out node, out slot, out index, out subIndex, out bitNo, out readIoType))
                {
                    return;
                }

                ushort result = deltaIoExtend.WriteBit(cardNo, node, slot, index, subIndex, bitNo, BitState.WriteValue, readIoType);
                BitState.ReturnCode = result;
                BitState.ResultMessage = $"WriteBit 返回码：{result}，写入值：{BitState.WriteValue}";
            }
            catch (Exception ex)
            {
                HandleException(ex, BitState, "WriteBit 执行异常");
            }
        }

        public void ReadDa()
        {
            try
            {
                IDeltaIoExtend deltaIoExtend;
                if (!TryGetDeltaIoExtend(out deltaIoExtend))
                {
                    return;
                }

                ushort cardNo;
                ushort node;
                ushort slot;
                ushort index;
                ushort subIndex;
                ushort byteSize;
                ushort ioType;
                if (!TryGetDaReadParameters(out cardNo, out node, out slot, out index, out subIndex, out byteSize, out ioType))
                {
                    return;
                }

                int rawValue;
                ushort result = deltaIoExtend.ReadDA(cardNo, node, slot, index, subIndex, out rawValue, byteSize, DaState.Signed, ioType);
                DaState.ReadRawValue = rawValue;
                DaState.ReturnCode = result;
                DaState.ResultMessage = $"ReadDA 返回码：{result}，结果：{rawValue}";
            }
            catch (Exception ex)
            {
                HandleException(ex, DaState, "ReadDA 执行异常");
            }
        }

        public void WriteDa()
        {
            try
            {
                IDeltaIoExtend deltaIoExtend;
                if (!TryGetDeltaIoExtend(out deltaIoExtend))
                {
                    return;
                }

                ushort cardNo;
                ushort node;
                ushort slot;
                ushort index;
                ushort subIndex;
                ushort byteSize;
                if (!TryGetDaWriteParameters(out cardNo, out node, out slot, out index, out subIndex, out byteSize))
                {
                    return;
                }

                ushort result = deltaIoExtend.WriteDA(cardNo, node, slot, index, subIndex, DaState.WriteRawValue, byteSize);
                DaState.ReturnCode = result;
                DaState.ResultMessage = $"WriteDA 返回码：{result}，写入值：{DaState.WriteRawValue}";
            }
            catch (Exception ex)
            {
                HandleException(ex, DaState, "WriteDA 执行异常");
            }
        }

        private DeltaBitTestState BuildBitState()
        {
            DeltaBitTestState state = new DeltaBitTestState();
            state.CardNo = 0;
            state.Node = 0;
            state.Slot = 0;
            state.Index = 0;
            state.SubIndex = 0;
            state.BitNo = 0;
            state.IoType = 1;
            state.ReadIoType = 1;
            return state;
        }

        private DeltaDaTestState BuildDaState()
        {
            DeltaDaTestState state = new DeltaDaTestState();
            state.CardNo = 0;
            state.Node = 0;
            state.Slot = 0;
            state.Index = 0;
            state.SubIndex = 0;
            state.ByteSize = 2;
            state.IoType = 1;
            return state;
        }

        private bool TryGetDeltaIoExtend(out IDeltaIoExtend deltaIoExtend)
        {
            RefreshCardStatus();
            if (_hardwareManager.TryGetDeltaIoExtend(out deltaIoExtend))
            {
                return true;
            }

            BitState.ResultMessage = "Delta卡未初始化或未实现 IDeltaIoExtend";
            DaState.ResultMessage = BitState.ResultMessage;
            return false;
        }

        private bool TryGetBitReadParameters(out ushort cardNo, out ushort node, out ushort slot, out ushort index, out ushort subIndex, out byte bitNo, out ushort ioType)
        {
            cardNo = 0;
            node = 0;
            slot = 0;
            index = 0;
            subIndex = 0;
            bitNo = 0;
            ioType = 0;

            bool isValid = TryGetUInt16(BitState.CardNo, "CardNo", out cardNo) &&
                           TryGetUInt16(BitState.Node, "Node", out node) &&
                           TryGetUInt16(BitState.Slot, "Slot", out slot) &&
                           TryGetHexUInt16(BitState.Index, "Index", out index) &&
                           TryGetHexUInt16(BitState.SubIndex, "SubIndex", out subIndex) &&
                           TryGetByte(BitState.BitNo, "BitNo", out bitNo) &&
                           TryGetUInt16(BitState.IoType, "IoType", out ioType);
            return isValid;
        }

        private bool TryGetBitWriteParameters(out ushort cardNo, out ushort node, out ushort slot, out ushort index, out ushort subIndex, out byte bitNo, out ushort readIoType)
        {
            cardNo = 0;
            node = 0;
            slot = 0;
            index = 0;
            subIndex = 0;
            bitNo = 0;
            readIoType = 0;

            bool isValid = TryGetUInt16(BitState.CardNo, "CardNo", out cardNo) &&
                           TryGetUInt16(BitState.Node, "Node", out node) &&
                           TryGetUInt16(BitState.Slot, "Slot", out slot) &&
                           TryGetHexUInt16(BitState.Index, "Index", out index) &&
                           TryGetHexUInt16(BitState.SubIndex, "SubIndex", out subIndex) &&
                           TryGetByte(BitState.BitNo, "BitNo", out bitNo) &&
                           TryGetUInt16(BitState.ReadIoType, "ReadIoType", out readIoType);
            return isValid;
        }

        private bool TryGetDaReadParameters(out ushort cardNo, out ushort node, out ushort slot, out ushort index, out ushort subIndex, out ushort byteSize, out ushort ioType)
        {
            cardNo = 0;
            node = 0;
            slot = 0;
            index = 0;
            subIndex = 0;
            byteSize = 0;
            ioType = 0;

            bool isValid = TryGetUInt16(DaState.CardNo, "CardNo", out cardNo) &&
                           TryGetUInt16(DaState.Node, "Node", out node) &&
                           TryGetUInt16(DaState.Slot, "Slot", out slot) &&
                           TryGetHexUInt16(DaState.Index, "Index", out index) &&
                           TryGetHexUInt16(DaState.SubIndex, "SubIndex", out subIndex) &&
                           TryGetUInt16(DaState.ByteSize, "ByteSize", out byteSize) &&
                           TryGetUInt16(DaState.IoType, "IoType", out ioType);
            return isValid;
        }

        private bool TryGetDaWriteParameters(out ushort cardNo, out ushort node, out ushort slot, out ushort index, out ushort subIndex, out ushort byteSize)
        {
            cardNo = 0;
            node = 0;
            slot = 0;
            index = 0;
            subIndex = 0;
            byteSize = 0;

            bool isValid = TryGetUInt16(DaState.CardNo, "CardNo", out cardNo) &&
                           TryGetUInt16(DaState.Node, "Node", out node) &&
                           TryGetUInt16(DaState.Slot, "Slot", out slot) &&
                           TryGetHexUInt16(DaState.Index, "Index", out index) &&
                           TryGetHexUInt16(DaState.SubIndex, "SubIndex", out subIndex) &&
                           TryGetUInt16(DaState.ByteSize, "ByteSize", out byteSize);
            return isValid;
        }

        private bool TryGetHexUInt16(int sourceValue, string parameterName, out ushort value)
        {
            string hexText = sourceValue.ToString(CultureInfo.InvariantCulture);
            return ushort.TryParse(hexText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out value)
                ? true
                : SetHexUInt16Error(parameterName, out value);
        }

        private bool SetHexUInt16Error(string parameterName, out ushort value)
        {
            value = 0;
            string message = $"参数 {parameterName} 超出十六进制 ushort 范围。";
            BitState.ResultMessage = message;
            DaState.ResultMessage = message;
            return false;
        }

        private bool TryGetUInt16(int sourceValue, string parameterName, out ushort value)
        {
            if (sourceValue < ushort.MinValue || sourceValue > ushort.MaxValue)
            {
                value = 0;
                string message = $"参数 {parameterName} 超出 ushort 范围。";
                BitState.ResultMessage = message;
                DaState.ResultMessage = message;
                return false;
            }

            value = (ushort)sourceValue;
            return true;
        }

        private bool TryGetByte(int sourceValue, string parameterName, out byte value)
        {
            if (sourceValue < byte.MinValue || sourceValue > byte.MaxValue)
            {
                value = 0;
                string message = $"参数 {parameterName} 超出 byte 范围。";
                BitState.ResultMessage = message;
                return false;
            }

            value = (byte)sourceValue;
            return true;
        }

        private void HandleException(Exception ex, DeltaBitTestState state, string operationName)
        {
            state.ResultMessage = operationName;
            LogManager.LogSysError(ex, true);
        }

        private void HandleException(Exception ex, DeltaDaTestState state, string operationName)
        {
            state.ResultMessage = operationName;
            LogManager.LogSysError(ex, true);
        }
    }
}
