package com.abbidot.tracker.util.bluetooth

import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.Intent
import android.text.TextUtils
import androidx.core.app.ActivityCompat.startActivityForResult
import com.abbidot.baselibrary.constant.ConState
import com.abbidot.baselibrary.constant.EventName
import com.abbidot.baselibrary.eventbus.XEventBus
import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.tracker.base.BaseActivity
import com.abbidot.tracker.bean.BleTrackDeviceBean
import com.abbidot.tracker.bean.ReceiveDeviceData
import com.abbidot.tracker.util.SocketUtilManageV2
import com.abbidot.tracker.util.Util
import com.clj.fastble.BleManager
import com.clj.fastble.callback.BleGattCallback
import com.clj.fastble.callback.BleNotifyCallback
import com.clj.fastble.callback.BleRssiCallback
import com.clj.fastble.callback.BleWriteCallback
import com.clj.fastble.data.BleDevice
import com.clj.fastble.data.BleScanState
import com.clj.fastble.exception.BleException
import com.clj.fastble.utils.HexUtil
import java.util.UUID


/**
 *Created  by .yzq on 2021/11/24/024.
 * @link
 * @description: ble蓝牙工具类
 */
class SRBleUtil private constructor() {

    //track设备蓝牙的开头名字
    val trackDeviceBleStartName = "AB_"

    //是否正在连接蓝牙设备
    var isBleConnecting = false

    //人为停止扫描设备，扫描中断
    var isScanInterrupt = false
    private var mSocketUtilManage: SocketUtilManageV2? = null

    /**
     * Bluetooth_Base_UUID定义为 00000000-0000-1000-8000-00805F9B34FB
     * 若16 bit UUID为xxxx，转换为128 bit UUID为0000xxxx-0000-1000-8000-00805F9B34FB
     */
    //发送消息给设备write
    private val serviceUUID = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e").toString()
    private val writeCharacteristicUUID =
        UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e").toString()

    //获取设备消息notify,read
    private val notifyServiceUUID = serviceUUID
    private val notifyCharacteristicUUID =
        UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e").toString()

    //蓝牙上报notify
    private val bleNotifyCharacteristicUUID =
        UUID.fromString("6e400004-b5a3-f393-e0a9-e50e24dcca9e").toString()

    //日志上报notify
    private val logG30NotifyCharacteristicUUID =
        UUID.fromString("6e400005-b5a3-f393-e0a9-e50e24dcca9e").toString()
    private val logG40ServiceUUID =
        UUID.fromString("0000d0d0-0000-1000-8000-00805f9b34fb").toString()
    private val logG40NotifyCharacteristicUUID =
        UUID.fromString("0000d0d2-0000-1000-8000-00805f9b34fb").toString()

    //保存已连接成功设备的全局变量
    private val mTrackDeviceList = mutableListOf<BleTrackDeviceBean>()
    private var mContext: Context? = null

    //SRBleUtil单例模式
    companion object {
        val instance: SRBleUtil by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            SRBleUtil()
        }
    }


    /*
      val scanRuleConfig = BleScanRuleConfig.Builder()
                // 只扫描指定的服务的设备，可选
                .setServiceUuids(serviceUuids)
                // 只扫描指定广播名的设备，可选
                .setDeviceName(true, names)
                // 只扫描指定mac的设备，可选
                .setDeviceMac(mac)
                // 连接时的autoConnect参数，可选，默认false
                .setAutoConnect(isAutoConnect)
                // 扫描超时时间，可选，默认10秒
                .setScanTimeOut(10000).build()
      BleManager.getInstance().initScanRule(scanRuleConfig)
     */
    fun init(app: Application) {
        mContext = app.applicationContext
        BleManager.getInstance().init(app)
        //是否显示框架内部日志，重连次数和重连时间间隔，以及操作超时时间。
        BleManager.getInstance().enableLog(AppUtils.isDebug()).operateTimeout = 5000
    }

    /**
     * 判断当前Android设备是否支持BLE。Android 4.3以后系统中加入了蓝牙BLE的功能。
     */
    fun isSupportBle(): Boolean = BleManager.getInstance().isSupportBle

    /**
     * 判断当前Android设备的蓝牙是否已经打开
     */
    fun isBleEnable(context: Context): Boolean {
//        BleManager.getInstance().isBlueEnable
        // 获取BluetoothManager服务
        val bluetoothManager =
            context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        // 获取BluetoothAdapter实例
        val bluetoothAdapter = bluetoothManager.adapter
        return bluetoothAdapter?.isEnabled ?: false
    }

    /**
     * 打开蓝牙。需要Manifest.permission.BLUETOOTH_CONNECT权限
     */
    @SuppressLint("MissingPermission")
    fun openBluetooth(context: Context) {
//        BleManager.getInstance().enableBluetooth()
        val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
    }

    /**
     * 通过startActivityForResult引导界面引导用户打开蓝牙
     * 需要Manifest.permission.BLUETOOTH_CONNECT权限
     */
    fun goOpenBluetooth(activity: Activity, requestCode: Int) {
        val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
        startActivityForResult(activity, intent, requestCode, null)
    }

    fun connect(bleDevice: BleDevice) {
        BleManager.getInstance().connect(bleDevice, object : BleGattCallback() {
            override fun onStartConnect() {
                isBleConnecting = true
                LogUtil.e("开始连接:${bleDevice.name}--${bleDevice.mac}")
            }

            override fun onConnectFail(bleDevice: BleDevice?, exception: BleException?) {
                isBleConnecting = false
                if (null != bleDevice) {
                    LogUtil.e("连接失败:${bleDevice.name}--${bleDevice.mac}")
                    notifyDeviceState(bleDevice, ConState.CONNECTION_FAIL)
                }
            }

            override fun onConnectSuccess(bleDevice: BleDevice, gatt: BluetoothGatt, status: Int) {
                LogUtil.e("连接成功:${bleDevice.name}--${bleDevice.mac}")
                isBleConnecting = false
                openNotify(
                    bleDevice, gatt, notifyServiceUUID, notifyCharacteristicUUID
                )
            }

            override fun onDisConnected(
                isActiveDisConnected: Boolean,
                bleDevice: BleDevice,
                gatt: BluetoothGatt,
                status: Int
            ) {
                LogUtil.e("蓝牙断开${bleDevice.name}，${bleDevice.mac}，activeDisConnected=$isActiveDisConnected,status=$status,mContext=$mContext")
                mContext?.apply {
                    //蓝牙关闭不需要发送断开连接，因为主页已监听蓝牙开关，发送断开连接
                    if (isBleEnable(this)) {
                        notifyDeviceState(bleDevice, ConState.DISCONNECTED)
                        if (!isActiveDisConnected) {
                            connect(bleDevice)
                        }
                    }
                }
            }
        })
    }

    fun isMacConnect(mac: String): Boolean {
        return BleManager.getInstance().isConnected(mac)
    }

    /**
     * 打开通道通知
     */
    fun openNotify(
        bleDevice: BleDevice, gatt: BluetoothGatt, uuidService: String, uuidNotify: String
    ) {
        val notifyId = uuidNotify.split("-")[0]
        BleManager.getInstance()
            .notify(bleDevice, uuidService, uuidNotify, object : BleNotifyCallback() {
                override fun onNotifySuccess() {
                    LogUtil.e("onNotifySuccess:${bleDevice.name}--${bleDevice.mac}")
                    //绑定
                    writeData(bleDevice, SRBleCmdUtil.instance.bindDevice())
                }

                override fun onNotifyFailure(exception: BleException?) {
                    LogUtil.e("onNotifyFailure--${bleDevice.mac},$exception")
                    //打开通道失败，断开连接重新连接
                    gatt.disconnect()
                    connect(bleDevice)
                }

                override fun onCharacteristicChanged(data: ByteArray?) {
                    val formatData = HexUtil.formatHexString(data, true)
                    LogUtil.e("设备响应指令,${bleDevice.mac},$notifyId->" + formatData)
                    data?.apply {
                        val data0 = SRBleCmdUtil.instance.byteToInt(data[0])
                        val data1 = SRBleCmdUtil.instance.byteToInt(data[1])
                        val data2 = SRBleCmdUtil.instance.byteToInt(data[2])
                        //绑定设备成功返回
                        if (data0 == 0x01 && data1 == 0x01 && data2 == 0x00) {
                            LogUtil.e("${bleDevice.mac},绑定成功")
                            //同步时间
                            writeData(bleDevice, SRBleCmdUtil.instance.setTime())
                        } else if (data0 == 0x16 && data1 == 0x01 && data2 == 0x00) {
                            //同步时间成功返回
                            LogUtil.e("${bleDevice.mac},同步时间成功")
                            openBleReportNotify(
                                bleDevice, notifyServiceUUID, bleNotifyCharacteristicUUID
                            )
                        } else if (data0 == 0x23 && data1 == 0x00) {
                            LogUtil.e("${bleDevice.mac},获取手机定位")
                            XEventBus.post(EventName.BleGetLocation, bleDevice.mac)
                        } else if (data0 == 0x24) {
                            LogUtil.e("${bleDevice.mac},蓝牙透传消息")
                            if (null == mSocketUtilManage) mSocketUtilManage = SocketUtilManageV2()
                            mContext?.let {
                                mSocketUtilManage?.initEasySocket(it, bleDevice.mac, data)
                            }
                        } else {
                            val deviceData = ReceiveDeviceData(bleDevice, data, bleDevice.mac)
                            XEventBus.post(EventName.DeviceReceiveData, deviceData)
                        }
                    }
                }
            })
    }

    /**
     * 打开蓝牙日志上报通道
     */
    private fun openBleReportNotify(
        bleDevice: BleDevice, uuidService: String, uuidNotify: String
    ) {
        BleManager.getInstance()
            .notify(bleDevice, uuidService, uuidNotify, object : BleNotifyCallback() {
                override fun onNotifySuccess() {
                    LogUtil.e("打开蓝牙上报通道成功：${bleDevice.name}--${bleDevice.mac}")
                    openG30LogReportNotify(
                        bleDevice, notifyServiceUUID, logG30NotifyCharacteristicUUID
                    )
                }

                override fun onNotifyFailure(exception: BleException?) {
                    LogUtil.e("打开蓝牙上报通道失败：${bleDevice.mac}，$exception")
                    openG30LogReportNotify(
                        bleDevice, notifyServiceUUID, logG30NotifyCharacteristicUUID
                    )
                }

                override fun onCharacteristicChanged(data: ByteArray?) {
                    data?.apply {
                        val formatData = HexUtil.formatHexString(data, true)
                        LogUtil.e("接收蓝牙上报通道数据：${bleDevice.mac}，$formatData")
                        val deviceData = ReceiveDeviceData(bleDevice, data, bleDevice.mac)
                        XEventBus.post(EventName.BleReport, deviceData)
                    }
                }
            })
    }

    /**
     * 打开g30日志上报通道
     */
    private fun openG30LogReportNotify(
        bleDevice: BleDevice, uuidService: String, uuidNotify: String
    ) {
        BleManager.getInstance()
            .notify(bleDevice, uuidService, uuidNotify, object : BleNotifyCallback() {
                override fun onNotifySuccess() {
                    LogUtil.e("打开日志上报通道成功：${bleDevice.name}--${bleDevice.mac}")
                    notifyDeviceState(bleDevice, ConState.CONNECTED)
                }

                override fun onNotifyFailure(exception: BleException?) {
                    LogUtil.e("打开日志上报通道失败：${bleDevice.mac}，$exception")
                    openG40LogReportNotify(
                        bleDevice, logG40ServiceUUID, logG40NotifyCharacteristicUUID
                    )
                }

                override fun onCharacteristicChanged(data: ByteArray?) {
                    data?.apply {
                        val deviceData = ReceiveDeviceData(bleDevice, data, bleDevice.mac)
                        XEventBus.post(EventName.LogReport, deviceData)
                    }
                }
            })
    }

    /**
     * 打开g40日志上报通道
     */
    private fun openG40LogReportNotify(
        bleDevice: BleDevice, uuidService: String, uuidNotify: String
    ) {
        BleManager.getInstance()
            .notify(bleDevice, uuidService, uuidNotify, object : BleNotifyCallback() {
                override fun onNotifySuccess() {
                    LogUtil.e("打开日志上报通道成功：${bleDevice.name}--${bleDevice.mac}")
                    notifyDeviceState(bleDevice, ConState.CONNECTED)
                }

                override fun onNotifyFailure(exception: BleException?) {
                    LogUtil.e("打开日志上报通道失败：${bleDevice.mac}，$exception")
                    notifyDeviceState(bleDevice, ConState.CONNECTED)
                }

                override fun onCharacteristicChanged(data: ByteArray?) {
                    data?.apply {
                        val deviceData = ReceiveDeviceData(bleDevice, data, bleDevice.mac)
                        XEventBus.post(EventName.LogReport, deviceData)
                    }
                }
            })
    }

    /**
     * 关闭通道通知
     */
    fun closeNotify(bleDevice: BleDevice, uuidService: String, uuidNotify: String) {
        BleManager.getInstance().stopNotify(bleDevice, uuidService, uuidNotify)
    }


    /**
     * 发送数据
     */
    fun writeData(bleDevice: BleDevice?, data: ByteArray) {
        if (null == bleDevice) return
        writeData(bleDevice, serviceUUID, writeCharacteristicUUID, data)
    }

    private fun writeData(
        bleDevice: BleDevice, uuidService: String, uuidWrite: String, data: ByteArray
    ) {
        LogUtil.d("send cmd:" + HexUtil.formatHexString(data, true))
        BleManager.getInstance()
            .write(bleDevice, uuidService, uuidWrite, data, false, object : BleWriteCallback() {
                override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
                    LogUtil.e(
                        "writeData onWriteSuccess data:" + HexUtil.formatHexString(data, true)
                    )
                }

                override fun onWriteFailure(exception: BleException?) {
                    LogUtil.e(
                        "writeData onWriteFailure data:" + HexUtil.formatHexString(
                            data, true
                        ) + " , error = " + exception.toString()
                    )
                }
            })
    }

    /**
     * 通知设备状态
     */
    private fun notifyDeviceState(bleDevice: BleDevice, @ConState consState: Int) {
        LogUtil.e("更新蓝牙连接状态consState=$consState")
        var device: BleTrackDeviceBean? = null

        for (trackDevice in mTrackDeviceList) {
            if (trackDevice.mac == bleDevice.mac) {
                device = trackDevice
                break
            }
        }
        if (null == device) {
            device = BleTrackDeviceBean()
            device.mac = bleDevice.mac
        }
        device.conState = consState
        device.bleDevice = bleDevice

        if (!mTrackDeviceList.contains(device)) {
            mTrackDeviceList.add(device)
        }

        XEventBus.post(EventName.ConnectDeviceState, device)
    }

    /**
     * 获取已连接指定的Mac设备
     */
    fun getConnectMacDevice(mac: String): BleTrackDeviceBean? {
        var trackDeviceBean: BleTrackDeviceBean? = null
        for (device in mTrackDeviceList) {
            if (device.mac == mac && BleManager.getInstance().isConnected(mac)) {
                trackDeviceBean = device
                break
            }
        }
        return trackDeviceBean
    }

    /**
     * 断开指定的蓝牙设备
     */
    fun disconnectToMac(mac: String) {
        if (TextUtils.isEmpty(mac)) {
            return
        }
        for (ble in mTrackDeviceList) {
            if (mac == ble.mac) {
                ble.bleDevice?.let {
//                    closeNotify(it, notifyServiceUUID, logNotifyCharacteristicUUID)
//                    closeNotify(it, notifyServiceUUID, bleNotifyCharacteristicUUID)
                    BleManager.getInstance().disconnect(it)
                }
                break
            }
        }
    }

    /**
     * 获取连接设备的实时信号
     */
    fun readConnectRssi(mac: String, callback: BleRssiCallback) {
        if (TextUtils.isEmpty(mac)) {
            return
        }
        for (ble in mTrackDeviceList) {
            if (mac == ble.mac) {
                ble.bleDevice?.let {
                    BleManager.getInstance().readRssi(it, callback)
                }
                break
            }
        }
    }

    /**
     * 发生数据给指定的Mac设备
     */
    fun isConnectBleSendCmdData(mac: String, byteArray: ByteArray) {
        if (TextUtils.isEmpty(mac)) {
            return
        }
        if (BleManager.getInstance().isConnected(mac)) {
            val trackDeviceBean = getConnectMacDevice(mac)
            trackDeviceBean?.let {
                writeData(it.bleDevice, byteArray)
            }
        }
    }


    /**
     *发送设备开启关闭led蓝牙指令
     */
    fun setBleLedSwitch(activity: BaseActivity<*>, bleDevice: BleDevice?, mode: Int) {
        //判断是否有蓝牙连接
        if (BleManager.getInstance().isConnected(bleDevice)) {
            Util.checkBluetoothPermissionsEnabled(activity, {
                writeData(
                    bleDevice, SRBleCmdUtil.instance.ledState(SRBleCmdUtil.CMD_WRITE, mode)
                )
            })
        }
    }

    /**
     * 取消蓝牙扫描
     */
    fun cancelBleScan(log: String = "") {
        if (BleManager.getInstance().scanSate == BleScanState.STATE_SCANNING) {
            isScanInterrupt = true
            XEventBus.post(
                EventName.ActionConDeviceState, ConState.DEVICE_NOT_FOUND
            )
            if (TextUtils.isEmpty(log)) LogUtil.e("正在扫描设备,取消蓝牙扫描")
            else LogUtil.e(log)
            BleManager.getInstance().cancelScan()
        }
    }
}