using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.Foundation;
using Windows.Security.Cryptography;


namespace Bluetoolth
{

    public enum BlueStatus
    {
        DisConnected,  //未连接
        Connecting,    //正在连接
        Connected      //已连接
    };

    public enum MsgType
    {
        NotifyTxt,
        BleDevice,
        BleSendData,
        BleRecData,
    }

    public class BleCore
    {

        private bool asyncLock = false;

        /// <summary>
        /// 搜索蓝牙设备对象
        /// </summary>
        private DeviceWatcher deviceWatcher;

        /// <summary>
        /// 当前连接的服务
        /// </summary>
        public GattDeviceService CurrentService { get; set; }

        /// <summary>
        /// 当前连接的蓝牙设备
        /// </summary>
        public BluetoothLEDevice CurrentDevice { get; set; }

        /// <summary>
        /// 写特征对象
        /// </summary>
        public GattCharacteristic CurrentWriteCharacteristic { get; set; }

        /// <summary>
        /// 写名称特征对象
        /// </summary>
        public GattCharacteristic CurrentNameCharacteristic { get; set; }

        /// <summary>
        /// 通知特征对象
        /// </summary>
        public GattCharacteristic CurrentNotifyCharacteristic { get; set; }

        /// <summary>
        /// 特性通知类型通知启用
        /// </summary>
        private const GattClientCharacteristicConfigurationDescriptorValue
            CHARACTERSITIC_NOTIFICATION_TYPE = GattClientCharacteristicConfigurationDescriptorValue.Notify;

        /// <summary>
        /// 存储检测到的设备
        /// </summary>
        private List<string> DevicesList = new List<string>();

        /// <summary>
        /// 定义搜索蓝牙设备委托
        /// </summary>
        /// <param name="type"></param>
        /// <param name="bluetoothLEDevice"></param>
        public delegate void DevicewatcherChangedEvent(MsgType type, BluetoothLEDevice bluetoothLEDevice);

        /// <summary>
        /// 搜索蓝牙事件
        /// </summary>
        public event DevicewatcherChangedEvent DevicewatcherChanged;

        /// <summary>
        /// 获取服务委托
        /// </summary>
        /// <param name="gattDeviceService"></param>
        public delegate void GattDeviceServiceAddedEvent(GattDeviceService gattDeviceService);

        /// <summary>
        /// 获取服务事件
        /// </summary>
        public event GattDeviceServiceAddedEvent GattDeviceServiceAdded;

        /// <summary>
        /// 获取特征委托
        /// </summary>
        /// <param name="gattCharacteristic"></param>
        public delegate void CharacteristicAddedEvent(GattCharacteristic gattCharacteristic);

        /// <summary>
        /// 获取特征事件
        /// </summary>
        public event CharacteristicAddedEvent CharacteristicAdded;

        /// <summary>
        /// 提示信息委托
        /// </summary>
        /// <param name="type"></param>
        /// <param name="message"></param>
        /// <param name="data"></param>
        public delegate void MessageChangedEvent(MsgType type, string message, byte[] data = null);

        /// <summary>
        /// 提示信息事件
        /// </summary>
        public event MessageChangedEvent MessageChanged;

        /// <summary>
        /// 当前连接蓝牙的Mac
        /// </summary>
        private string CurrentDeviceMAC { get; set; }

        public BleCore()
        {

        }


        /// <summary>
        /// 搜索蓝牙设备 方法1
        /// </summary>
        public void StartBleDevicewatcher_1()
        {

            string[] requestedProperties = {
                "System.Devices.Aep.DeviceAddress",
                "System.Devices.Aep.IsConnected",
                "System.Devices.Aep.Bluetooth.Le.IsConnectable" ,
                "System.Devices.Aep.SignalStrength",
                "System.Devices.Aep.IsPresent"
           };
            string aqsAllBluetoothLEDevices = "(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")";

            string Selector = "System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\"";
            string selector = "(" + Selector + ")" + " AND (System.Devices.Aep.CanPair:=System.StructuredQueryType.Boolean#True OR System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#True)";


            this.deviceWatcher =
                DeviceInformation.CreateWatcher(
                 //  aqsAllBluetoothLEDevices,

                 //  BluetoothLEDevice.GetDeviceSelectorFromPairingState(false),
                 selector,
                    requestedProperties,
                    DeviceInformationKind.AssociationEndpoint);

            //在监控之前注册事件
            this.deviceWatcher.Added += DeviceWatcher_Added;
            this.deviceWatcher.Stopped += DeviceWatcher_Stopped;
            this.deviceWatcher.Updated += DeviceWatcher_Updated; ;
            this.deviceWatcher.Start();
            string msg = "自动发现设备中..";
            this.MessageChanged(MsgType.NotifyTxt, msg);
        }



        BluetoothLEAdvertisementWatcher watcher;
        /// <summary>
        /// 搜索蓝牙设备 方法2
        /// </summary>
        public void StartBleDevicewatcher()
        {
            watcher = new BluetoothLEAdvertisementWatcher();

            watcher.ScanningMode = BluetoothLEScanningMode.Active;

            // only activate the watcher when we're recieving values >= -80
            watcher.SignalStrengthFilter.InRangeThresholdInDBm = -80;

            // stop watching if the value drops below -90 (user walked away)
            watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90;

            // register callback for when we see an advertisements
            watcher.Received += OnAdvertisementReceived;
            watcher.Stopped += Watcher_Stopped;

            // wait 5 seconds to make sure the device is really out of range
            watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
            watcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);

            // starting watching for advertisements
            watcher.Start();
            string msg = "自动发现设备中..";

            // this.MessageChanged(MsgType.NotifyTxt, msg);
        }

        private void Watcher_Stopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args)
        {
            DevicesList.Clear();
            string msg = "自动发现设备停止";
            this.MessageChanged(MsgType.NotifyTxt, msg);
        }

        private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
        {
            BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress).Completed = async (asyncInfo, asyncStatus) =>
            {
                if (asyncStatus == AsyncStatus.Completed)
                {
                    if (asyncInfo.GetResults() == null)
                    {
                        //this.MessAgeChanged(MsgType.NotifyTxt, "没有得到结果集");
                    }
                    else
                    {
                        BluetoothLEDevice currentDevice = asyncInfo.GetResults();
                        if (currentDevice.Name.StartsWith("Bluetooth"))
                        {
                            return;
                        }

                        Boolean contain = false;
                        foreach (string deviceId in DevicesList)//过滤重复的设备
                        {
                            if (deviceId == currentDevice.DeviceId)
                            {
                                contain = true; break;
                            }
                        }

                        string tmpMAC = "";
                        byte[] _Bytes1 = BitConverter.GetBytes(currentDevice.BluetoothAddress);
                        Array.Reverse(_Bytes1);

                        tmpMAC = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();

                        if (!contain)
                        {
                            this.DevicesList.Add(currentDevice.DeviceId);
                            this.MessageChanged(MsgType.NotifyTxt, "发现设备:" + currentDevice.Name + "  address:" + tmpMAC);
                            this.DevicewatcherChanged(MsgType.BleDevice, currentDevice);

                            //  currentDevice = null;
                        }
                        /*
                        if (CurrentDevice == null  && CurrentDeviceMAC == tmpMAC)
                        {//自动重连
                            CurrentDevice = currentDevice;
                       
                            //获取服务
                            this.CurrentDevice.GetGattServicesAsync().Completed =  (asynServe, asyncStatu) =>
                            {
                                if (asyncStatu == AsyncStatus.Completed)
                                {
                                    var sevices = asynServe.GetResults().Services;
                                    foreach (GattDeviceService ser in sevices)
                                    {
                                        if (ser.Uuid.ToString() == Utility.UUID_SERVER)
                                        {
                                            this.CurrentService = ser;
                                            break;
                                        }

                                    }
                                }
                                else
                                {
                                    this.CurrentDevice = null;
                                }
                            };

                            if (this.CurrentService != null)
                            {
                                //获取特征值
                                this.CurrentService.GetCharacteristicsAsync().Completed =  (asynChara, asyncStatu) =>
                                {
                                    if (asyncStatu == AsyncStatus.Completed)
                                    {
                                        var chara = asynChara.GetResults().Characteristics;
                                        foreach (GattCharacteristic c in chara)
                                        {
                                            if (c.Uuid.ToString() == Utility.UUID_Name)
                                            {
                                                this.CurrentNameCharacteristic = c;
                                                break;
                                            }
                                        }
                                    }
                                };
                            }
                            else
                            {//删除设备
                                this.CurrentDevice = null;
                                this.CurrentService = null;
                                return;
                            }


                            if (this.CurrentNameCharacteristic != null)
                            {
                                string msg = "已重连设备连接设备<" + this.CurrentDeviceMAC + "> ..";
                                this.MessageChanged(MsgType.NotifyTxt, msg);
                            }

                        }

                        */
                    }

                }
            };
        }



        /// <summary>
        /// 停止搜索
        /// </summary>
        public void StopBleDeviceWatcher()
        {
            if (deviceWatcher != null)
                this.deviceWatcher.Stop();

            if (watcher != null && watcher.Status == BluetoothLEAdvertisementWatcherStatus.Started)
                watcher.Stop();
        }

        /// <summary>
        /// 获取发现的蓝牙设备
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
        {
            this.MessageChanged(MsgType.NotifyTxt, "发现设备:" + args.Id);
            this.Matching(args.Id, args);
        }

        private void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate args)
        {

        }

        /// <summary>
        /// 停止搜索蓝牙设备
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void DeviceWatcher_Stopped(DeviceWatcher sender, object args)
        {
            string msg = "自动发现设备停止";
            this.MessageChanged(MsgType.NotifyTxt, msg);
        }


        /// <summary>
        /// 匹配
        /// </summary>
        /// <param name="device"></param>
        public void StartMatching(BluetoothLEDevice device)
        {
            //  Dispose(false);
            this.CurrentDevice = device;
        }

        /// <summary>
        /// 获取蓝牙服务
        /// </summary>
        public async void FindService()
        {
            /*var gattServices = this.CurrentDevice.GattServices;
            foreach(GattDeviceService ser in gattServices)
            {
                this.GattDeviceServiceAdded(ser);
            }*/

            this.CurrentDevice.GetGattServicesAsync().Completed = async (asyncInfo, asyncStatu) =>
            {
                if (asyncStatu == AsyncStatus.Completed)
                {
                    var sevices = asyncInfo.GetResults().Services;
                    foreach (GattDeviceService ser in sevices)
                    {
                        this.GattDeviceServiceAdded(ser);
                        //  FindCharacteristic(ser);
                    }
                }
            };
        }


        public async void FindCharacteristic(GattDeviceService gattDeviceService)
        {
            /* this.CurrentService = gattDeviceService;
             foreach(var c in gattDeviceService.GetAllCharacteristics())
             {
                 this.CharacteristicAdded(c);
             }*/


            gattDeviceService.GetCharacteristicsAsync().Completed = async (asyncInfo, asyncStatu) =>
            {
                if (asyncStatu == AsyncStatus.Completed)
                {
                    var chara = asyncInfo.GetResults().Characteristics;
                    foreach (GattCharacteristic c in chara)
                    {
                        this.CharacteristicAdded(c);
                    }
                }
            };
        }


        /// <summary>
        /// 获取操作
        /// </summary>
        /// <param name="gattCharacteristic"></param>
        /// <returns></returns>
        public async Task SetOpteron(GattCharacteristic gattCharacteristic)
        {
            if (gattCharacteristic.CharacteristicProperties == GattCharacteristicProperties.WriteWithoutResponse)
            {
                this.CurrentWriteCharacteristic = gattCharacteristic;
            }
            if (gattCharacteristic.CharacteristicProperties == GattCharacteristicProperties.Notify)
            {
                this.CurrentNotifyCharacteristic = gattCharacteristic;
                this.CurrentNotifyCharacteristic.ProtectionLevel = GattProtectionLevel.Plain;
                this.CurrentNotifyCharacteristic.ValueChanged += Characteristic_ValueChanged;
                await this.EnableNotifications(CurrentNotifyCharacteristic);
            }


            if (gattCharacteristic.CharacteristicProperties == (GattCharacteristicProperties.Read | GattCharacteristicProperties.Write))
            {
                this.CurrentNameCharacteristic = gattCharacteristic;
            }

            if (!IsConnect)
                this.Connect();
        }

        bool IsConnect = false;

        private async Task Connect()
        {
            IsConnect = true;
            byte[] _Bytes1 = BitConverter.GetBytes(this.CurrentDevice.BluetoothAddress);
            Array.Reverse(_Bytes1);
            this.CurrentDeviceMAC = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();

            string msg = "正在连接设备<" + this.CurrentDeviceMAC + "> ..";
            this.MessageChanged(MsgType.NotifyTxt, msg);
            this.CurrentDevice.ConnectionStatusChanged += CurrentDevice_ConnectionStatusChanged;
        }

        private void CurrentDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args)
        {
            if (sender.ConnectionStatus == BluetoothConnectionStatus.Disconnected &&
                   CurrentDeviceMAC != null)
            {
                this.DevicesList.Remove(sender.DeviceId);

                string msg = "设备已断开";
                MessageChanged(MsgType.NotifyTxt, msg);


                // if(!asyncLock)
                {
                    asyncLock = true;
                    this.CurrentDevice?.Dispose();
                    this.CurrentDevice = null;

                    this.CurrentNotifyCharacteristic = null;
                    this.CurrentWriteCharacteristic = null;
                    this.CurrentNameCharacteristic = null;
                    //  SelectDeviceFromIdAsync(CurrentDeviceMAC);
                }
            }
            else
            {
                string msg = "设备已连接";
                MessageChanged(MsgType.NotifyTxt, msg);
            }
        }

        /// <summary>
        /// 搜索到的蓝牙设备
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        private async Task Matching(string id, DeviceInformation args = null)
        {

            try
            {
                BluetoothLEDevice.FromIdAsync(id).Completed = async (asyncInfo, asyncStatus) =>
                {
                    if (asyncStatus == AsyncStatus.Completed)
                    {
                        BluetoothLEDevice bleDevice = asyncInfo.GetResults();
                        if (bleDevice.Name.StartsWith("Bluetooth"))
                        {
                            return;
                        }
                        if (CurrentDeviceMAC != null)
                        {//自动重连
                            CurrentDevice = bleDevice;

                            //获取服务
                            this.CurrentDevice.GetGattServicesAsync().Completed = async (asynServe, asyncStatu) =>
                            {
                                if (asyncStatu == AsyncStatus.Completed)
                                {
                                    var sevices = asynServe.GetResults().Services;
                                    foreach (GattDeviceService ser in sevices)
                                    {
                                        if (ser.Uuid.ToString() == Utility.UUID_SERVER)
                                        {
                                            this.CurrentService = ser;
                                            break;
                                        }

                                    }
                                }
                            };

                            if (this.CurrentService != null)
                            {
                                //获取特征值
                                this.CurrentService.GetCharacteristicsAsync().Completed = async (asynChara, asyncStatu) =>
                                {
                                    if (asyncStatu == AsyncStatus.Completed)
                                    {
                                        var chara = asynChara.GetResults().Characteristics;
                                        foreach (GattCharacteristic c in chara)
                                        {
                                            if (c.Uuid.ToString() == Utility.UUID_Name)
                                            {
                                                this.CurrentNameCharacteristic = c;
                                                break;
                                            }
                                        }
                                    }
                                };
                            }


                            if (this.CurrentNameCharacteristic != null)
                            {
                                string msg = "已重连设备连接设备<" + this.CurrentDeviceMAC + "> ..";
                                this.MessageChanged(MsgType.NotifyTxt, msg);
                            }

                        }

                        string tmp = this.DevicesList.Where(p => p == bleDevice.DeviceId).FirstOrDefault();


                        if (tmp == null)
                        {//没有添加过

                            this.DevicesList.Add(bleDevice.DeviceId);

                            this.DevicewatcherChanged(MsgType.BleDevice, bleDevice);
                            bleDevice = null;
                        }
                    }
                };
            }
            catch (Exception e)
            {
                string msg = "没有发现设备" + e.ToString();
                this.MessageChanged(MsgType.NotifyTxt, msg);
                this.StopBleDeviceWatcher();
            }
        }

        public void DisConnect()
        {
            /* GattSession.FromDeviceIdAsync(CurrentDevice.BluetoothDeviceId).Completed = async (asyncInfo, asyncStatus) =>
             {
                 if (asyncStatus == AsyncStatus.Completed)
                 {
                     GattSession session = asyncInfo.GetResults();
                     if(session != null)
                     {
                         session.Dispose();
                         this.MessageChanged(MsgType.NotifyTxt, "主动断开session");
                         Dispose();
                     }
                 }
             };*/

            Dispose();
        }


        /// <summary>
        /// 主动断开连接
        /// </summary>
        public void Dispose(bool IsTip = true)
        {
            IsConnect = false;
            CurrentDeviceMAC = null;

            CurrentService?.Dispose();

            if (CurrentDevice != null)
                CurrentDevice.ConnectionStatusChanged -= CurrentDevice_ConnectionStatusChanged;

            CurrentDevice?.Dispose();

            CurrentDevice = null;
            CurrentService = null;


            CurrentNameCharacteristic = null;
            CurrentWriteCharacteristic = null;
            CurrentNotifyCharacteristic = null;
            // if(IsTip)
            this.MessageChanged(MsgType.NotifyTxt, "主动断开连接");
            // else
            {//清除蓝牙列表
                this.DevicesList.Clear();
            }
        }

        /// <summary>
        /// 按MAC地址直接组装设备ID查找设备
        /// </summary>
        /// <param name="MAC"></param>
        /// <returns></returns>
        public async Task SelectDeviceFromIdAsync(string MAC)
        {
            CurrentDeviceMAC = MAC;
            CurrentDevice = null;

            BluetoothAdapter.GetDefaultAsync().Completed = async (asyncInfo, asyncStatus) =>
            {
                if (asyncStatus == AsyncStatus.Completed)
                {
                    BluetoothAdapter bluetoothAdapter = asyncInfo.GetResults();
                    // ulong 转为byte数组 
                    byte[] _Bytes1 = BitConverter.GetBytes(bluetoothAdapter.BluetoothAddress);
                    Array.Reverse(_Bytes1);
                    string macAddress = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();
                    string Id = "BluetoothLe#BluetoothLe" + macAddress + "-" + MAC;

                    await Matching(Id);
                }
            };
        }



        /// <summary>
        /// 设置特征对象为接收通知对象
        /// </summary>
        /// <param name="characteristic"></param>
        /// <returns></returns>
        public async Task EnableNotifications(GattCharacteristic characteristic)
        {
            string msg = "收通知对象=" + CurrentDevice.ConnectionStatus;
            this.MessageChanged(MsgType.NotifyTxt, msg);

            characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(CHARACTERSITIC_NOTIFICATION_TYPE).Completed = async (asyncInfo, asyncStatus) =>
            {
                if (asyncStatus == AsyncStatus.Completed)
                {
                    GattCommunicationStatus status = asyncInfo.GetResults();
                    if (status == GattCommunicationStatus.Unreachable)
                    {
                        msg = "设备不可用";
                        this.MessageChanged(MsgType.NotifyTxt, msg);
                        if (CurrentNotifyCharacteristic != null && !asyncLock)
                        {
                            await this.EnableNotifications(CurrentNotifyCharacteristic);
                        }
                    }
                    asyncLock = false;
                    msg = "设备连接状态" + status;
                    this.MessageChanged(MsgType.NotifyTxt, msg);
                }
            };
        }

        /// <summary>
        /// 接受到蓝牙数据
        /// </summary>
        private void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
        {
            byte[] data;
            CryptographicBuffer.CopyToByteArray(args.CharacteristicValue, out data);
            string str = BitConverter.ToString(data);
            this.MessageChanged(MsgType.BleRecData, str, data);
        }

        /// <summary>
        /// 发送数据接口
        /// </summary>
        /// <returns></returns>
        public async Task Write(byte[] data)
        {
            if (CurrentWriteCharacteristic != null)
            {
                CurrentWriteCharacteristic.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(data), GattWriteOption.WriteWithResponse);
                string str = "发送数据:" + BitConverter.ToString(data);
                this.MessageChanged(MsgType.BleSendData, str, data);
            }

        }

        /// <summary>
        /// 发送数据接口
        /// </summary>
        /// <returns></returns>
        public async Task WriteName(byte[] data)
        {
            if (CurrentNameCharacteristic != null)
            {
                CurrentNameCharacteristic.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(data), GattWriteOption.WriteWithResponse);
                string str = "发送数据:" + BitConverter.ToString(data);
                this.MessageChanged(MsgType.BleSendData, str, data);
            }
        }

    }
}