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 Kxware.Connectivity.Remoting.Messages;
using MECF.Framework.Common.Communications.Tcp.Socket.Framing;
using MECF.Framework.Common.Communications.Tcp.Socket.Server.APM;
using MECF.Framework.Common.Communications.Tcp.Socket.Server.APM.EventArgs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Xml;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps
{
    /// <summary>
    /// 昂坤测温使用Trigger触发，
    /// 返回温度数组，依次包含CH平均，Wafer平均，Tray平均
    /// 目前仅支持一个托盘计算
    /// </summary>
    public class AKunTriggerTemp : TempSensorBase
    {
        private TcpSocketServer _socketServer;
        private TcpSocketSession _session;
        private int _port;
        private string _ip;

        /// <summary>
        /// 温度不变Trig
        /// </summary>
        private readonly R_TRIG _rTrigTempNoChange = new();

        /// <summary>
        /// 通讯超时时间秒
        /// </summary>
        private const int TCP_TIME_OUT = 6;

        /// <summary>
        /// 晶圆的数量
        /// </summary>
        private readonly int _waferNum=1;

        /// <summary>
        /// 晶圆的数量
        /// </summary>
        private readonly int _trayNum=1;

        ///// <summary>
        ///// 一个测温通道对应一个集合索引
        ///// </summary>
        //private readonly List<AKunTriggerChannelWaferTempData[]> _chWaferTempDataList=new ();

        private double _trayTemp;
        //private bool[] _calZone;

        /// <summary>
        /// 反射率数组
        /// </summary>
        private List<double[]> _reflects;

        //private AKunTriggerChannelWaferTempData[] _tempDataArray;

        private AKunTriggerTempDataManager _aKunTempManager;

        /// <summary>
        /// 定义时钟监视数据发送，有可能通讯还在数据不发送
        /// </summary>
        private DeviceTimer _timer = new DeviceTimer();

        public AKunTriggerTemp(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule)
        {
            var maxWaferNum = node.GetAttribute("WaferNum");

            //if (string.IsNullOrWhiteSpace(maxWaferNum))
            //    _waferNum = SC.GetStringValue($"System.InchType") == "Inch6" ? 8 : 5;
            //else
            //    int.TryParse(maxWaferNum, out _waferNum);

            //var trayNum = node.GetAttribute("TrayNum");
            //if (!string.IsNullOrWhiteSpace(trayNum) && int.TryParse(trayNum, out var maxT))
            //    _trayNum = maxT;

            RTrigs.Add(_rTrigTempNoChange);
        }

        protected override void InitTempDataFilter()
        {
            TempBasFunction = new TempBasFunction(Name, MinimalTemp, _waferNum);
            _aKunTempManager = new(_waferNum, MinimalTemp);

            _trayTemp = MinimalTemp;

            TempBasFunction.SetTempCh(_waferNum);

            Temp = Enumerable.Repeat(MinimalTemp, _waferNum).ToArray();
            //_calZone = new bool[_waferNum];
            //PM可以选的Wafer注册,初始索引需要加上通道数
            for (var i = 0; i < _waferNum; i++)
            {
                var index = i;
                DATA.Subscribe($"TempSensor.{Name}.Wafer{i + 1}.Temp", () => Temp[index]);
            }

            //PM可以选的Tray注册,初始索引需要加上通道数和Wafer数量
            DATA.Subscribe($"TempSensor.{Name}.Tray.Temp", () => _trayTemp);

            //DATA.Subscribe($"TempSensor.{Name}.CalZone", () => _calZone);

            #region 注册反射率数据
            _reflects = Enumerable
                .Range(0, _waferNum)
                .Select(i => new double[3])
                .ToList();

            for (int i = 0; i < _waferNum; i++)
            {
                var index = i;
                DATA.Subscribe($"TempSensor.{Name}.Wafer{index + 1}.Reflect1", () => _reflects[index][0]);
                DATA.Subscribe($"TempSensor.{Name}.Wafer{index + 1}.Reflect2", () => _reflects[index][1]);
                DATA.Subscribe($"TempSensor.{Name}.Wafer{index + 1}.Reflect3", () => _reflects[index][2]);
            }

            #endregion 注册反射率数据

            OP.Subscribe($"{Module}.AKunTriggerTemp.MarkerActive", (function, args) =>
            {
                ProcessWriteMessage($"MarkerActive={args[0]}");
                return true;
            });

            OP.Subscribe($"{Module}.AKunTriggerTemp.RunID", (function, args) =>
            {
                ProcessWriteMessage($"RunID={args[0]}");
                return true;
            });

            OP.Subscribe($"{Module}.AKunTriggerTemp.StepCode", (function, args) =>
            {
                ProcessWriteMessage($"StepCode={args[0]}");
                return true;
            });
        }

        protected override bool HandleInitialize()
        {
            InitController();
            return true;
        }

        private void InitController()
        {
            var data = SC.GetStringValue($"{ScBasePath}.{Name}.Address").Split(':');
            _ip = data[0]; ;
            _port = Convert.ToInt32(data[1]);
            TcpSocketServerConfiguration config = new TcpSocketServerConfiguration()
            {
                FrameBuilder = new LineBasedFrameBuilder(new LineDelimiter("\r\n")),
            };
            _socketServer = new TcpSocketServer(IPAddress.Parse(_ip), _port, config);
            _socketServer.ClientConnected += ClientConnected;
            _socketServer.ClientDisconnected += ClientDisconnected;
            _socketServer.ClientDataReceived += ClientDataReceived;
        }

        protected override void HandleMonitor()
        {
            if (_socketServer == null)
                return;

            if (!_socketServer.IsListening)
            {
                _socketServer.Listen();
            }

            if (_timer.IsTimeout())
            {
                _timer.Stop();
                if (IsProcess())
                {
                    TempBasFunction.PMPostLog(Module, $"TCP server received temp data timeout {TCP_TIME_OUT}s, {_ip}:{_port}, {Module}.{Name}", EV.PostWarningLog);
                    TempBasFunction.SetPmIoForInterlock(Module, true);
                }
            }
        }

        private void ClientDataReceived(object sender, TcpClientDataReceivedEventArgs e)
        {
            OnReadMessage(Encoding.UTF8.GetString(e.Data, e.DataOffset, e.DataLength));
        }

        private void OnReadMessage(string message)
        {
            _timer.Stop();
            if (IsEnableLog)
                LOG.Write(message);

            if (_aKunTempManager.ProcessReceivedData(message))
                TempReadThread();
            else
                TempBasFunction.PMPostLog(Module, $"TCP server received error temp data from AKun {_ip}:{_port}, {Module}.{Name}\r\ninf:'{message}'", EV.PostWarningLog);

            _timer.Start(TCP_TIME_OUT * 1000);
        }

        private void ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e)
        {
            _socketServer.CloseSession(_session.SessionKey);
            _session = null;
            TempBasFunction.PMPostLog(Module, $"Can not connect with {_ip}:{_port}, {Module}.{Name}", EV.PostWarningLog);
            TempBasFunction.SetPmIoForInterlock(Module, true);
        }

        private void ClientConnected(object sender, TcpClientConnectedEventArgs e)
        {
            _session = e.Session;
            TempBasFunction.PMPostLog(Module, $"Connected with {_ip}:{_port}, {Module}.{Name}", EV.PostInfoLog);
            TempBasFunction.SetPmIoForInterlock(Module, false);
            _timer.Start(TCP_TIME_OUT * 1000);
        }

        private void ProcessWriteMessage(string msg)
        {
            TempBasFunction.PMPostLog(Module, $"{Name}： Tcp Socket Write Message {msg}", EV.PostInfoLog);
            if (_session != null)
                _session.Send(Encoding.ASCII.GetBytes(msg));
            else
                TempBasFunction.PMPostLog(Module, $"Tcp Socket Server is  null {_ip}:{_port}, {Module}.{Name}", EV.PostWarningLog);
        }

        protected override bool DoTempReadThread()
        {
            return true;
        }

        private bool TempReadThread()
        {
            // get temp. points according to the "IsSimulatorMode" system config.

            var temps = IsSimMode ? RandomTemps(_waferNum) : HandleReadTemp();
            _rTrigReadTempFailed.CLK = temps == null || temps.Length != (_waferNum);
            if (_rTrigReadTempFailed.Q)
            {
                LOG.Error(temps != null
                    ? $"{this} {_waferNum} temperature data wanted but {temps.Length} points read."
                    : $"{this} None temperature data read from controller.");
            }

            // Too less temp. points read from the sensor.
            if (_rTrigReadTempFailed.M)
                return true;

            if (IsProcess() && AllTempNoChange(temps))//检测所有通道温度是否变化
                return true;

            // Get the right temp value from the filter
            for (var i = 0; i < Temp.Length; i++)
            {
                Temp[i] = temps[i];
            }
            return true;
        }

        private bool AllTempNoChange(double[] tempArray)
        {
            int noChangeCount = TempBasFunction.AllTempNoChangeCount(tempArray, out string resuonInf);
            if (noChangeCount >= 18)
            {
                _rTrigTempNoChange.CLK = true;
                if (_rTrigTempNoChange.Q)
                {
                    TempBasFunction.PMPostLog(Module, $"{this} all temp no change: \r\n" +
                                                      $"{resuonInf}", EV.PostWarningLog);
                }

                return true;
            }

            return false;
        }

        protected override double[] HandleReadTemp()
        {
            //昂坤的温度数据上位机在这里被动接受
            //_calZone = _aKunTempManager.GetCalZone();
            _trayTemp = _aKunTempManager.GetTrayTemp();
            _reflects = _aKunTempManager.GetReflectValue();

            return _aKunTempManager.GetWaferTemp();
        }

        public override void Terminate()
        {
            _socketServer.Shutdown();
        }

        public override void Reset()
        {
            _timer.Start(TCP_TIME_OUT * 1000);
            base.Reset();
        }
    }
}