using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using Venus_RT.Modules;
using MECF.Framework.Common.Communications;
using MECF.Framework.Common.Equipment;
using Venus_Core;
using Aitex.Core.RT.SCCore;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using EPD.Data;
using Venus_RT.Devices;
using System.Text.RegularExpressions;

namespace Venus_RT.Devices.EPD
{
    
    public class EPDClient : JetEPDBase
    {

        private EPDSocketClient _socketClient;
        private string _ip;
        private int _port;
        private int _channel;
        private Stopwatch _heartBeatTimer = new Stopwatch();
        private bool _isHeartBeatReceived=true;
        private readonly R_TRIG _epdIdle = new R_TRIG();

        private bool _captured;
        public override bool Captured { get { return _captured; }}

        private bool _connected = false;
        public override bool IsEPDConnected { get { return _connected; } }

        private EDPStatus _status;
        public override EDPStatus Status { get { return _status; } }
        private List<string> _cfgFileList;
        public override List<string> CFGFileList { get { return _cfgFileList; }  }

        public string EPDVersion { get; private set; }
        public string EPDState { get; private set; }
        public string SensorStatus { get; private set; }
        public string EPDRunStatus { get; private set; }
        public string EPDMode { get; private set; }

        public EPDClient(ModuleName mod)
        {
            Name = VenusDevice.EndPoint.ToString();
            Module = mod.ToString();
            var ipaddress= SC.GetStringValue($"{mod.ToString()}.EPD.IPAddress");
            var ipaddressValue = ipaddress.Split(':');
            if (ipaddressValue.Length == 2)
            {
                _ip = ipaddressValue[0];
                _port = System.Convert.ToInt32(ipaddressValue[1]);
            }

            _channel = SC.GetValue<int>($"{Module}.EPD.ChannelNumber");

            _socketClient = new EPDSocketClient();
            _socketClient.OnConnect += OnConnect;
            _socketClient.OnDisconnect += OnDisConnect;
            _socketClient.OnSocketSend += OnEPDSocketSend;
            _socketClient.OnSocketReceive += OnEPDSocketReceive;
            _socketClient.OnEPDReply += OnEPDReply;
            _socketClient.OnError += OnError;
        }

        public override bool Initialize()
        { 
            _socketClient.Connect(_ip, _port);
            _socketClient.ConnectEPD();
            _socketClient.SetMode(2);       // 1 local; 2 remote
            _socketClient.SetRunStatus(4);  // 1 Monitor; 2 Save; 3:Capture; 4:Process
            _socketClient.QueryConfigList();
            return true;
        }

        public override void Monitor()
        {
            HeartBeat();
        }

        public override void Reset()
        { }

        public override void Terminate()
        {
            _status = EDPStatus.Idle;
            _socketClient.DisconnectEPD();
            _socketClient.Disconnect();
        }

        public override void RecipeStart(string recipe)
        {
            _captured = false;
            _socketClient.RecipeStart(_channel, recipe);
            _status = EDPStatus.Running;
        }

        public override void RecipeStop()
        {
            _socketClient.RecipeStop(_channel);
            _status = EDPStatus.Idle;
        }

        public override void StepStart(string cfgName, int Index)
        {
            _socketClient.Start((byte)_channel, cfgName);
            _status = EDPStatus.Running;
        }

        public override void StepStop()
        {
            _socketClient.Stop((byte)_channel);
        }

        private void HeartBeat()
        {
            //_socketClient.SendHeartBeat();

            _epdIdle.CLK = Status == EDPStatus.Idle;
            if (_epdIdle.Q)
            {
                _socketClient.SendHeartBeat();
                _heartBeatTimer.Restart();
                _isHeartBeatReceived = false;
            }
            else if(_epdIdle.M)
            {
                if(_heartBeatTimer.ElapsedMilliseconds > 30000)
                {
                    if (!_isHeartBeatReceived && !SC.GetValue<bool>("System.IsSimulatorMode"))
                    {
                        LOG.Write(eEvent.ERR_ENDPOINT, Module, "HeartBeat Error, EndPoint Device did not response in 5 seconds");
                    }

                    _socketClient.SendHeartBeat();
                    _heartBeatTimer.Restart();
                    _isHeartBeatReceived = false;
                }
            }
            else
            {
                _heartBeatTimer.Stop();
            }
        }

        private void OnConnect()
        {
            LOG.Write(eEvent.INFO_ENDPOINT, Module, "Endpoint connected");
        }

        private void OnDisConnect()
        {
            LOG.Write(eEvent.INFO_ENDPOINT, Module, "Endpoint disconnected");
        }

        private void OnEPDSocketReceive(string type, byte[] data, int length)
        {
            var content = StringJoin(" ", data, length);
            //LOG.Write(eEvent.INFO_ENDPOINT, Module, $"Endpoint Receive: {content}");
        }

        private void OnEPDSocketSend(string type, byte[] data)
        {
            var content = StringJoin(" ", data, data.Length);
            if(type != "HeartBeat")
            {
                LOG.Write(eEvent.INFO_ENDPOINT, Module, $"Endpoint Send=> Type:{type}, Data:{content}");
            }
        }

        private void OnError(int command, int errorCode)
        {
            var strError = errorCode.ToString();
            if (EPDDefine.ErrorMap.ContainsKey(errorCode))
                strError = EPDDefine.ErrorMap[errorCode];

            string ErrorInfo = $"EndPoint Command {(EPDCommand)command} Failed: {strError}";
            LOG.Write(eEvent.ERR_ENDPOINT, Module, ErrorInfo);
        }

        private void OnEPDReply(EPDCommand cmd, object obj)
        {
            switch (cmd)
            {
                case EPDCommand.SetWaferInfo:
                    break;
                case EPDCommand.QueryCfgList:
                    if (obj is List<string>)
                        _cfgFileList = (List<string>)obj;
                    break;
                case EPDCommand.QueryState:
                    if (obj is ushort state && EPDDefine.StateMap.ContainsKey(state))
                        EPDState = EPDDefine.StateMap[state];
                    break;
                case EPDCommand.QueryVer:
                    EPDVersion = obj.ToString();
                    break;
                case EPDCommand.Connect:
                    _connected = true;
                    break;
                case EPDCommand.HeartBeat:
                    _isHeartBeatReceived = true;
                    break;
                case EPDCommand.QueryRunStatus:
                    if (obj is ushort sta && EPDDefine.RunStatusMap.ContainsKey(sta))
                    {
                        EPDRunStatus = EPDDefine.RunStatusMap[sta];
                    }
                    break;
                case EPDCommand.QueryOperateMode:
                    if (obj is ushort mode && EPDDefine.ModeMap.ContainsKey(mode))
                    {
                        EPDMode = EPDDefine.ModeMap[mode];
                    }
                    break;
                case EPDCommand.GetSensorStatus:
                    if (obj is List<string> statusLst && statusLst.Count >= 2)
                    {
                        SensorStatus = statusLst[0];
                    }
                    break;
                case EPDCommand.GetRecipesList:
                    if (obj is List<string> objs)
                    {
                        _cfgFileList = objs.GetRange(3, objs.Count - 3);
                        SensorStatus = objs[0];
                    }
                    break;
                case EPDCommand.Event:
                    var lst = obj as List<object>;
                    //LOG.Write(0,"test11111111111111111111111XX"+lst[0].ToString());
                    if (lst[0] is int type && type == 7)
                        _captured = true;
                    break;
                case EPDCommand.AsciiEvent:
                    if (obj.ToString() == "ENDPOINT")
                        _captured = true;
                    break;
                case EPDCommand.QueryChannelCount:
                case EPDCommand.QueryChannalNames:
                case EPDCommand.RecipeStart:
                case EPDCommand.RecipeStop:
                case EPDCommand.Start:
                case EPDCommand.Stop:
                default:
                    break;
            }
        }

        private string StringJoin(string separator, byte[] values, int length)
        {
            if (values == null || values.Length == 0)
                return string.Empty;

            if (separator == null)
                separator = string.Empty;

            var sb = new StringBuilder($"{values[0]:X2}");
            for (int i = 1; i < length; i++)
                sb.Append($"{separator}{values[i]:X2}");

            return sb.ToString();
        }
        public override void QueryConfigList()
        {
            _socketClient.QueryConfigList();
        }
    }
}