using BPASmartClient.Helper;
using BPASmartClient.Message;
using BPASmartClient.Modbus;
using BPASmartClient.DosingSystem.ViewModel;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BPASmartClient.DosingSystem.Model
{
    public class DeviceInquire
    {
        private volatile static DeviceInquire _Instance;
        public static DeviceInquire GetInstance => _Instance ?? (_Instance = new DeviceInquire());
        private DeviceInquire() { }

        string IPSegment = "192.168.0.";

        ConcurrentDictionary<string, DeviceStatus> DeviceLists = new ConcurrentDictionary<string, DeviceStatus>();
        List<string> InvalidIP = new List<string>();//无效 IP 集合
        List<string> IPLists = new List<string>();//启动 Ping 任务IP集合
        ConcurrentQueue<string> IPQueues = new ConcurrentQueue<string>();//pincomplete 完成队列

        public void Init()
        {
            IpAddressLines();
            ThreadManage.GetInstance().StartLong(new Action(() =>
            {
                if (IPQueues.Count >= IPLists.Count)
                    IpAddressLines();
                Thread.Sleep(5000);
            }), "配料机设备上线监听", true);
        }

        public void Rescan()
        {
            InvalidIP.Clear();
        }

        public DeviceStatus GetDevice(string ip)
        {
            if (ip != null)
            {
                var res = DeviceLists.Values.FirstOrDefault(p => p.IpAddress == ip);
                if (res != null) return res;
            }
            return new DeviceStatus();
        }

        private void IpAddressLines()
        {
            IPLists.Clear();
            IPQueues.Clear();
            for (int i = 1; i <= 255; i++)
            {
                if (!InvalidIP.Contains($"{IPSegment}{i}") && !DeviceLists.ContainsKey($"{IPSegment}{i}"))
                {
                    IPLists.Add($"{IPSegment}{i}");
                }
            }

            IPLists.ForEach((item) =>
            {
                Ping myPing = new Ping();
                myPing.PingCompleted += new PingCompletedEventHandler(_myPing_PingCompleted);
                myPing.SendAsync(item, 1000, null);
            });
        }

        private void _myPing_PingCompleted(object sender, PingCompletedEventArgs e)
        {
            if (e.Reply.Status == IPStatus.Success)
            {
                string ip = e.Reply.Address.ToString();
                if (!DeviceLists.ContainsKey(ip))
                {
                    DeviceStatus DS = new DeviceStatus();
                    DS.modbusTcp.IsReconnect = false;

                    DS.modbusTcp.ConnectOk = new Action(() =>
                    {
                        string DeviceName = DS.modbusTcp.GetString(DeviceAddress.DeviceName, 20);
                        if (DeviceName.Length > 0)
                        {
                            DeviceLists.TryAdd(ip, DS);
                            DeviceLists[ip].Init(DeviceName);
                            DeviceLists[ip].modbusTcp.IsReconnect = false;
                            App.Current.Dispatcher.Invoke(new Action(() =>
                            {
                                DeviceListViewModel.devices.Add(new Devices()
                                {
                                    DeviceName = DeviceName,
                                    IpAddress = ip
                                });

                                for (int i = 0; i < Json<LocaPar>.Data.Recipes.Count; i++)
                                {
                                    for (int m = 0; m < Json<LocaPar>.Data.Recipes.ElementAt(i).RawMaterials.Count; m++)
                                    {
                                        if (Json<LocaPar>.Data.Recipes.ElementAt(i).RawMaterials.ElementAt(m).DeviceIp == ip)
                                        {
                                            Json<LocaPar>.Data.Recipes.ElementAt(i).RawMaterials.ElementAt(m).RawMaterialName = DeviceName;
                                        }
                                    }
                                }

                                if (!NewRecipeViewModel.RawMaterialNames.Contains(DeviceName))
                                    NewRecipeViewModel.RawMaterialNames.Add(DeviceName);

                            }));
                        }
                        else
                        {
                            if (!InvalidIP.Contains(ip)) InvalidIP.Add(ip);
                        }
                    });

                    DS.modbusTcp.ConnectFail = new Action(() =>
                    {
                        if (!InvalidIP.Contains(ip)) InvalidIP.Add(ip);
                        MessageLog.GetInstance.Show($"{ip}连接失败");
                    });

                    DS.modbusTcp.Disconnect = new Action(() =>
                    {
                        if (InvalidIP.Contains(ip)) InvalidIP.Remove(ip);
                        var res = DeviceListViewModel.devices.FirstOrDefault(P => P.IpAddress == ip);
                        if (res != null && DeviceListViewModel.devices.Contains(res))
                            App.Current.Dispatcher.Invoke(new Action(() =>
                            {
                                DeviceListViewModel.devices.Remove(res);
                                if (!NewRecipeViewModel.RawMaterialNames.Contains(res.DeviceName))
                                    NewRecipeViewModel.RawMaterialNames.Remove(res.DeviceName);
                            }));
                        if (DeviceLists.ContainsKey(ip)) DeviceLists[ip].Dispose();
                    });

                    Task.Run(new Action(() =>
                    {
                        DS.modbusTcp.ModbusTcpConnect(ip, 502);
                        IPQueues.Enqueue(e.Reply.Address.ToString());
                    }));
                }
                else IPQueues.Enqueue(e.Reply.Address.ToString());
            }
            else IPQueues.Enqueue(e.Reply.Address.ToString());
        }
    }

    public class DeviceStatus
    {

        #region 对象属性声明
        public string DeviceName = String.Empty;
        public string IpAddress => modbusTcp.IPAdress;

        /// <summary>
        /// 设备状态
        /// </summary>
        public RawMaterialDeviceStatus deviceStatus { get; set; } = new RawMaterialDeviceStatus();

        public ModbusTcp modbusTcp = new ModbusTcp();

        public bool IsConnected => modbusTcp.Connected;
        #endregion

        public void Init(string DeviceName)
        {
            this.DeviceName = DeviceName;
            if (modbusTcp.Connected)
            {
                ThreadManage.GetInstance().StartLong(new Action(() =>
                {
                    //获取设备运行状态
                    var res = this.modbusTcp.Read(DeviceAddress.RunStatus);
                    if (res != null && res is ushort[] ushortValue)
                    {
                        if (ushortValue.Length >= 1) deviceStatus.RunStatus = ushortValue[0];
                    }

                    //获取设备料仓剩余重量
                    deviceStatus.WeightFeedback = this.modbusTcp.GetUint(DeviceAddress.WeightFeedback) * 10;

                    Thread.Sleep(100);
                }), $"{DeviceName} 开始监听", true);
            }
        }

        public void SetDeviceName(string name)
        {
            this.modbusTcp.Write(DeviceAddress.DeviceName, new ushort[20]);
            this.modbusTcp.SetString(DeviceAddress.DeviceName, name);
        }

        public void StatusReset()
        {
            this.modbusTcp.Write(DeviceAddress.RunStatus, (ushort)0);
        }

        public void Dispose()
        {
            ThreadManage.GetInstance().StopTask($"{DeviceName} 开始监听");
        }

        public void Start(uint Value)
        {
            if (modbusTcp.Connected)
            {
                modbusTcp.SetUint(DeviceAddress.WeightSet, Value);//写入配方量
                modbusTcp.Write(DeviceAddress.Start, (ushort)1);//设备启动写入
            }
        }
    }

}
