using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ArduinoBluetoothAPI;

namespace SmartBowSDK
{
    public class BluetoothAim_SDK : MonoBehaviour
    {
        public SmartBowHelper smartBowHelper;

        public BluetoothDeviceConfig deviceConfig;
        private BluetoothHelper _bluetoothHelper;
        private BluetoothHelperService _bluetoothService;
        private BluetoothHelperCharacteristic _characteristicWrite;
        private static HashSet<object> _ScanLocker = new HashSet<object>();

        private int _receivedDataCount = 0;
        public string macAddress = null;

        public BluetoothStatusEnum bluetoothStatus;

        private BluetoothWindows _bluetoothWindows;

        private void SetStatus(BluetoothStatusEnum newStatus)
        {
            BluetoothStatusEnum oldStatus = bluetoothStatus;
            if (oldStatus == newStatus) return;
            bluetoothStatus = newStatus;
            SmartBowLogger.Log(this, $"oldStatus[{oldStatus}]=>newStatus[{newStatus}]");
            if (newStatus == BluetoothStatusEnum.None)
            {
                _bluetoothHelper = null;
                _bluetoothService = null;
                _characteristicWrite = null;
                _receivedDataCount = 0;
                macAddress = null;
                _battery = 0;
                moduleInited = false;
            }
            smartBowHelper.InvokeOnBluetoothStatusChanged(oldStatus, newStatus);
        }

        void Awake()
        {
            DontDestroyOnLoad(gameObject);
            deviceConfig = BluetoothDeviceConfig.GetDefault();

        }

        void Update()
        {
            LoopHandleCommands();
        }

        private static int _NoneToConnectingStep = 0;

        public BluetoothWindows CreateWindowBLE() {

            //如果是window环境，直接实例化一个BluetoothWindows
            if (BluetoothWindows.IsWindows())
            {
                _bluetoothWindows = new BluetoothWindows();
                _bluetoothWindows.OnConnected = OnConnected_windows;
                _bluetoothWindows.OnConnectionFailed = OnConnectionFailed_windows;
                _bluetoothWindows.OnCharacteristicChanged = OnCharacteristicChanged_windows;

                return _bluetoothWindows;
            }

            return null;
        }
        public void Connect()
        {
            if (BluetoothWindows.IsWindows())
            {
                if (bluetoothStatus == BluetoothStatusEnum.None)
                {
                    _bluetoothWindows.Connect();
                    SetStatus(BluetoothStatusEnum.Connecting);
                }
                return;
            }
            if (_ScanLocker.Count > 0) return;
            if (bluetoothStatus != BluetoothStatusEnum.None) return;
            if (_NoneToConnectingStep > 0) return;
            _NoneToConnectingStep = 1;
            if (Application.platform == RuntimePlatform.Android)
            {
                if (!BluetoothHelperAndroid_SDK.IsBluetoothEnabled())
                {
                    HandleConnectError(BluetoothError.BluetoothNotEnabled, "蓝牙开关未打开");
                    return;
                }
                if (BluetoothHelperAndroid_SDK.RequestBluetoothPermissions(() =>
                {
                    _NoneToConnectingStep = 0;
                    Connect();
                }, (permission) =>
                {
                    if (permission.Contains("LOCATION"))
                    {
                        HandleConnectError(BluetoothError.LocationPermissionNotGranted, "尚未授予定位权限");
                    }
                    else if (permission.Contains("BLUETOOTH"))
                    {
                        HandleConnectError(BluetoothError.ScanPermissionNotGranted, "尚未授予扫描附近设备权限");
                    }
                })) return;
            }
            try
            {
                BluetoothHelper.BLE = true;
                _bluetoothHelper = BluetoothHelper.GetNewInstance();
                _bluetoothHelper.OnConnected += OnConnected;
                _bluetoothHelper.OnConnectionFailed += OnConnectionFailed;
                _bluetoothHelper.OnCharacteristicChanged += OnCharacteristicChanged;
                _bluetoothHelper.OnScanEnded += OnScanEnded;
                _bluetoothHelper.ScanNearbyDevices();
                _NoneToConnectingStep = 2;
            }
            catch (Exception e)
            {
                HandleConnectError(BluetoothError.Unknown, e.ToString());
            }
            if (_NoneToConnectingStep == 2)
            {
                _NoneToConnectingStep = 0;
                _ScanLocker.Add(_bluetoothHelper);
                SetStatus(BluetoothStatusEnum.Connecting);
            }
        }

        private void HandleConnectError(BluetoothError error, string message)
        {
            _NoneToConnectingStep = 0;
            smartBowHelper.InvokeOnBluetoothError(error, message);
        }

        public void Disconnect()
        {
            //断开连接时候清除AimDeviceInfo
            ResetAimDeviceInfoToNull();

            if (BluetoothWindows.IsWindows())
            {
                if (_bluetoothWindows.Disconnect())
                    SetStatus(BluetoothStatusEnum.None);
                return;
            }
            if (_bluetoothHelper != null)
                _bluetoothHelper.Disconnect();
            SetStatus(BluetoothStatusEnum.None);
        }

        void OnConnected(BluetoothHelper helper)
        {
            if (helper != _bluetoothHelper) return;
            SetStatus(BluetoothStatusEnum.Connected);
            foreach (BluetoothHelperService service in helper.getGattServices())
            {
                if (service.getName().ToLower().StartsWith(deviceConfig.service))
                {
                    _bluetoothService = service;
                    foreach (BluetoothHelperCharacteristic characteristic in service.getCharacteristics())
                    {
                        if (characteristic.getName().ToLower().StartsWith(deviceConfig.characteristicWrite))
                        {
                            _characteristicWrite = characteristic;
                        }
                        else if (characteristic.getName().ToLower().StartsWith(deviceConfig.characteristicNotify))
                        {
                            BluetoothHelperCharacteristic c = new BluetoothHelperCharacteristic(characteristic.getName());
                            c.setService(_bluetoothService.getName());
                            _bluetoothHelper.Subscribe(c);
                        }
                    }
                }
            }
            StartCoroutine(InitWhenConnected());
        }
        void OnConnected_windows()
        {
            SetStatus(BluetoothStatusEnum.Connected);
            StartCoroutine(InitWhenConnected());
        }

        void OnConnectionFailed(BluetoothHelper helper)
        {
            if (helper != _bluetoothHelper) return;
            SetStatus(BluetoothStatusEnum.None);
        }
        void OnConnectionFailed_windows()
        {
            SetStatus(BluetoothStatusEnum.None);
        }

        void OnCharacteristicChanged(BluetoothHelper helper, byte[] value, BluetoothHelperCharacteristic characteristic)
        {
            if (helper != _bluetoothHelper) return;
            if (bluetoothStatus != BluetoothStatusEnum.Connected) return;
            byte[] bytes = value;
            if (macAddress == null && _receivedDataCount++ < 500) ParseMacAddress(value);
            smartBowHelper.aimHandler.OnDataReceived(bytes);
        }
        void OnCharacteristicChanged_windows(string deviceId, byte[] value)
        {
            OnCharacteristicChanged(null, value, null);
        }

        void OnScanEnded(BluetoothHelper helper, LinkedList<BluetoothDevice> nearbyDevices)
        {
            _ScanLocker.Remove(helper);
            if (helper != _bluetoothHelper) return;
            foreach (BluetoothDevice device in nearbyDevices)
            {
                SmartBowLogger.Log(this, $"发现设备{device.DeviceName}");
                //if (device.DeviceName == deviceConfig.deviceName)
                //后续匹配名字 可以是多个设备
                if (deviceConfig.deviceName.Contains(device.DeviceName))
                {
                    _bluetoothHelper.setDeviceName(device.DeviceName);
                    _bluetoothHelper.Connect();
                    SmartBowLogger.Log(this, $"匹配设备{device.DeviceName}");
                    return;
                }
            }
            SetStatus(BluetoothStatusEnum.None);
            smartBowHelper.InvokeOnBluetoothError(BluetoothError.ScanNotFoundTargetDevice, "扫描结束后未发现目标设备");
        }

        private float _lastWriteDataTime;
        bool WriteData(string data)
        {
            try
            {
                if (BluetoothWindows.IsWindows())
                {
                    return _bluetoothWindows.Write(data);
                }
                BluetoothHelperCharacteristic c = new BluetoothHelperCharacteristic(_characteristicWrite.getName());
                c.setService(_bluetoothService.getName());
                _bluetoothHelper.WriteCharacteristic(c, data);
                _lastWriteDataTime = Time.realtimeSinceStartup;
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                return false;
            }
        }
        bool WriteByteData(byte[] data)
        {
            try
            {
                if (BluetoothWindows.IsWindows())
                {
                    return _bluetoothWindows.WriteByte(data);
                }
                BluetoothHelperCharacteristic c = new BluetoothHelperCharacteristic(_characteristicWrite.getName());
                c.setService(_bluetoothService.getName());
                _bluetoothHelper.WriteCharacteristic(c, data);
                _lastWriteDataTime = Time.realtimeSinceStartup;
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                return false;
            }
        }
        public bool moduleInited;
        private string _connectedHandlerID = "";
        IEnumerator InitWhenConnected()
        {
            string myConnectedHandlerID = Guid.NewGuid().ToString();
            _connectedHandlerID = myConnectedHandlerID;
            yield return new WaitForSecondsRealtime(BluetoothWindows.IsWindows() ? 0.3f : 2.2f);
            Queue<string> cmds = new Queue<string>(new string[] { "M", "b", "b", "1" });
            while (cmds.Count > 0)
            {
                if (bluetoothStatus != BluetoothStatusEnum.Connected || myConnectedHandlerID != _connectedHandlerID) yield break;
                string cmd = cmds.Dequeue();
                WriteData(cmd);
                yield return new WaitForSecondsRealtime(0.3f);
            }
            if (bluetoothStatus != BluetoothStatusEnum.Connected || myConnectedHandlerID != _connectedHandlerID) yield break;
            StartCoroutine(LoopRequestBattery(myConnectedHandlerID));
            moduleInited = true;
            smartBowHelper.InvokeOnBluetoothModuleInited();

        }

        private int _battery = 0;
        public int battery
        {
            get => _battery;
            set
            {
                _battery = value;
                SmartBowLogger.Log(this, "Battery缓存成功");
            }
        }

        IEnumerator LoopRequestBattery(string myConnectedHandlerID)
        {
            while (bluetoothStatus == BluetoothStatusEnum.Connected && myConnectedHandlerID == _connectedHandlerID)
            {
                yield return new WaitForSecondsRealtime(10);
                AddCommandToQueue("b");
            }
        }

        private List<string> _commands = new List<string>();
        void LoopHandleCommands()
        {
            if (bluetoothStatus != BluetoothStatusEnum.Connected || !moduleInited)
            {
                if (_commands.Count > 0) _commands.Clear();
                return;
            }
            if (Time.realtimeSinceStartup - _lastWriteDataTime < 0.2f) return;
            if (_commands.Count == 0) return;
            string cmd = _commands[0];
            _commands.RemoveAt(0);
            WriteData(cmd);
        }
        bool AddCommandToQueue(string cmd)
        {
            if (bluetoothStatus != BluetoothStatusEnum.Connected || !moduleInited) return false;
            //如果待插入的指令跟队尾的指令一样，就不要插入了，因为冗余的指令无意义
            if (_commands.Count > 0 && _commands[_commands.Count - 1].Equals(cmd)) return true;
            _commands.Add(cmd);
            return true;
        }

        public void ReplyInfraredShoot()
        {

            if (bluetoothStatus != BluetoothStatusEnum.Connected || !moduleInited) return;
            WriteData("I");
        }

        public void ReplyByte(byte[] value)
        {

            if (bluetoothStatus != BluetoothStatusEnum.Connected || !moduleInited) return;
            WriteByteData(value);
        }

        public bool RequestOpen9Axis()
        {
            return AddCommandToQueue("3");
        }

        public bool RequestClose9Axis()
        {
            return AddCommandToQueue("4");
        }

        public bool RequestOpenInfrared()
        {
            return AddCommandToQueue("w");
        }

        public bool RequestCloseInfrared()
        {
            return AddCommandToQueue("s");
        }

        void ParseMacAddress(byte[] bytes)
        {
            string mac = System.Text.Encoding.ASCII.GetString(bytes);
            if (mac != null) mac = mac.Trim();
            if (CheckIsMacValid(mac))
            {
                #region 根据aimDeviceInfo存在添加一个判断
                if (aimDeviceInfo != null) {
                    //需要增加一个判断，判断是否对应的mac设备。不是需要进行重新连接
                    if (!aimDeviceInfo.bInitMac)
                    {
                        SmartBowLogger.Log(this, "设置设备mac：" + mac);
                        SetAimDeviceMac(mac);
                    }
                    else if (aimDeviceInfo.mac != mac)
                    {
                        SmartBowLogger.LogError(this, "设备不一样，断开连接");
                        Disconnect();
                        //抛出一个错误，给用户处理其他业务流程
                        smartBowHelper.InvokeOnBluetoothError(BluetoothError.MacAddressAndDeviceMismatch, "验证设备MAC和记录的MAC不匹配！");
                        return;
                    }
                }
                #endregion

                macAddress = mac;
                SmartBowLogger.Log(this, "MacAddress解析成功");
                //获取MacAddress对应的校准记录
                string macXXX = macAddress;
                smartBowHelper.smartBowNetwork.GetCalibrateRecord(macXXX, (record) =>
                {
                    if (macAddress != macXXX) return;
                    smartBowHelper.aimHandler.ResumeCalibrateRecord(record);
                });
            }
            else SmartBowLogger.LogWarning(this, "MacAddress解析失败");
        }

        bool CheckIsMacValid(string mac)
        {
            if (mac == null) return false;
            if (!mac.StartsWith("{")) return false;
            if (!mac.EndsWith("}")) return false;
            if (!mac.Contains(":")) return false;
            char[] validChars = { '{', '}', ':', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
            foreach (var c in mac.ToCharArray())
            {
                if (Array.IndexOf(validChars, c) == -1) return false;
            }
            if (mac.Length != 19) return false;
            string macNoneFrame = mac.Substring(1, mac.Length - 2);
            string[] macNoneFrameSplits = macNoneFrame.Split(':');
            if (macNoneFrameSplits.Length != 6) return false;
            foreach (var item in macNoneFrameSplits)
            {
                if (item.Length != 2) return false;
                foreach (var c in item.ToCharArray())
                    if (Array.IndexOf(validChars, c) < 3) return false;
            }
            return true;
        }



        #region 记录的设备处理部分
        //连接时候判断信息。存在对象则连接需要判断MAC
        //记录一个设备
        AimDeviceInfo aimDeviceInfo = null;
        //用户初始化一个保存数据的操作的id。
        //不设置情况下不给进行相关操作
        string keyPrefix = "aim-device-info-";
        string userTags = "";
        int deviceId = -1;

        //清空对应id的数据
        public void onClearAimDeviceInfoByDeviceId(string _userTags, int _deviceId)
        {
            string deviceInfo = PlayerPrefs.GetString(keyPrefix + _userTags + _deviceId, "");
            if (deviceInfo != "") {
                PlayerPrefs.DeleteKey(keyPrefix + _userTags + _deviceId);
                ResetAimDeviceInfoToNull();
            }
        }
        public AimDeviceInfo onGetAimDeviceInfos(string _userTags, int _deviceId)
        {
            OnGetAimDeviceInfo(_userTags, _deviceId);
            //SmartBowLogger.Log(this, $"onGetAimDeviceInfos[{JsonUtility.ToJson(aimDeviceInfo)}]");
            return aimDeviceInfo;
        }
        //根据设置的
        void OnGetAimDeviceInfo(string _userTags, int _deviceId)
        {
            string deviceInfo = PlayerPrefs.GetString(keyPrefix + _userTags + _deviceId, "");
            if (deviceInfo != "")
            {
                aimDeviceInfo = JsonUtility.FromJson<AimDeviceInfo>(deviceInfo);//这里的类是依据最外层{}决定的
            }
        }
        void OnSaveAimDeviceInfo(string _userTags, int _deviceId)
        {
            if (_userTags.Length == 0)
            {
                SmartBowLogger.LogError(this, $"存储标识不存在!");
                return;
            }
            SmartBowLogger.Log(this, $"OnSaveAimDeviceInfo [{JsonUtility.ToJson(aimDeviceInfo)}]");
            PlayerPrefs.SetString(keyPrefix + _userTags + _deviceId, JsonUtility.ToJson(aimDeviceInfo));
        }

        //连接蓝牙调用。连接时候创建一个连接信息，用于记录mac 是否要验证
        //传入一个id用于区分是哪个设备
        //bRecreateDeviceInfo 是否重新创建
        public void initAimDeviceInfo(string _userTags, int _deviceId, bool bRecreateDeviceInfo)
        {
            userTags = _userTags;
            deviceId = _deviceId;

            if (bRecreateDeviceInfo)
            {
                //直接覆盖设备信息
                onRecreateAimDeviceInfoById();
            }
            else
            {
                //获取设备信息。没有创建
                onCreateAimDeviceInfoById();
            }
        }

        //是否存在AimDeviceInfo，存在获取，不存在创建；
        void onCreateAimDeviceInfoById()
        {
            ResetAimDeviceInfoToNull();
            OnGetAimDeviceInfo(userTags, deviceId);
            if (aimDeviceInfo == null)
            {
                aimDeviceInfo = new AimDeviceInfo(deviceId);
                OnSaveAimDeviceInfo(userTags, deviceId);
            }
        }

        //直接覆盖新元素
        void onRecreateAimDeviceInfoById()
        {
            // 使用Lambda表达式删除特定条件的元素
            ResetAimDeviceInfoToNull();
            //添加一个新元素
            aimDeviceInfo = new AimDeviceInfo(deviceId);
            //更新信息
            OnSaveAimDeviceInfo(userTags, deviceId);
        }

        //APP连接需进行MAC地址的比对。
        void SetAimDeviceMac(string _mac)
        {
            aimDeviceInfo.setInitMac(_mac);
            OnSaveAimDeviceInfo(userTags, deviceId);
        }

        public void ResetAimDeviceInfoToNull()
        {
            aimDeviceInfo = null;
        }

        #endregion
    }

    #region 添加一个记录设备连接的信息，主要用于判断mac地址是否连接操作

    [Serializable]//需要在转换为json格式的类的上方添加序列化
    public class AimDeviceInfo
    {
        public int id; //区分用户设备对应的id
        public bool bInitMac = false; //是否初始化Mac
        public string mac; //记录当前

        public AimDeviceInfo(int _id)
        {
            this.id = _id;
        }

        public void setInitMac(string macTemp)
        {
            bInitMac = true;
            mac = macTemp;
        }

        public void resetInitMac()
        {
            bInitMac = false;
            mac = "";
        }
    }

    #endregion
}
