package com.common.bluetooth

import android.Manifest
import android.app.Activity
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.os.Build
import android.os.IBinder
import android.util.Log.d
import android.util.Log.e
import androidx.core.content.ContextCompat.checkSelfPermission
import com.common.bluetooth.BtConstants.BLUETOOTH_TYPE
import com.common.bluetooth.adapter.BluetoothClientBLEAdapter
import com.common.bluetooth.bean.CommonMsg
import com.common.bluetooth.callback.BLEClientListener
import com.common.bluetooth.callback.BleMsgReceiverListener
import com.common.bluetooth.interfaces.IBluetoothClient
import com.common.bluetooth.service.BLEClientService
import com.common.bluetooth.service.BLEClientService.BLEClientBinder
import com.common.bluetooth.service.BLEReceiveService
import com.common.bluetooth.service.BLEReceiveService.ReceiverBinder
import com.common.bluetooth.service.BluetoothLeClient
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observer
import io.reactivex.rxjava3.disposables.Disposable
import java.util.concurrent.atomic.AtomicBoolean

/**
 * 蓝牙管理类
 *
 * @author wangym
 * @since 2021-10-28
 */
object BtManager {
    const val TAG = "BtManager"

    /**
     * 蓝牙客户端
     */
    private var mBtClient: IBluetoothClient? = null

    /**
     * 客户端服务
     */
    private var clientService: BLEClientService? = null

    /**
     * 服务端服务
     */
    private var serverService: BLEReceiveService? = null

    /**
     * 消息接收监听
     */
    var msgReceiverListener: BleMsgReceiverListener? = null

    /**
     * 蓝牙客户端监听
     */
    var clientListener: BLEClientListener? = null

    /**
     * 是否绑定了服务端
     */
    private var isBindServer: AtomicBoolean = AtomicBoolean(false)

    /**
     * 是否绑定了客户端
     */
    private var isBindClient: AtomicBoolean = AtomicBoolean(false)

    /**
     * 当前使用的编码 默认是UTF-8
     * 在传输前自动设置即可
     */
    var curCharset = Charsets.UTF_8

    /**
     * 当前连接的设备MAC
     */
    var curConnectMac = ""

    /**
     * 初始化蓝牙服务端模块
     */
    fun initServer(context: Context, btType: BLUETOOTH_TYPE) {
        mBtClient = BluetoothClientBLEAdapter(BluetoothLeClient.getInstance(context))
        mBtClient!!.checkBluetoothDevice(btType)
        initReceiverService(context)
    }

    /**
     * 初始化蓝牙客户端模块
     */
    fun initClient(context: Activity, btType: BLUETOOTH_TYPE) {
        mBtClient = BluetoothClientBLEAdapter(BluetoothLeClient.getInstance(context))
        mBtClient!!.checkBluetoothDevice(btType)
        initClientService(context)
    }


    /**
     * 初始化接收端服务
     */
    private fun initReceiverService(context: Context) {
        val intent = Intent(context, BLEReceiveService::class.java)
        // 标志位BIND_AUTO_CREATE是的服务中onCreate得到执行,onStartCommand不会执行
        context.bindService(intent, receiverConn, Context.BIND_AUTO_CREATE)
        isBindServer.set(true)
    }

    /**
     * 初始化客户端服务
     */
    private fun initClientService(context: Context) {
        val intent = Intent(context, BLEClientService::class.java)
        // 标志位BIND_AUTO_CREATE是的服务中onCreate得到执行,onStartCommand不会执行
        context.bindService(intent, clientConn, Context.BIND_AUTO_CREATE)
        isBindClient.set(true)
    }

    private val receiverConn: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            serverService = (service as ReceiverBinder).service
            serverService?.setMsgReceiveListener(object : BleMsgReceiverListener {
                override fun onMsgReceive(msg: ByteArray) {
                    msgReceiverListener?.onMsgReceive(msg)
                }
            })
        }

        override fun onServiceDisconnected(name: ComponentName) {}
    }

    private val clientConn: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            clientService = (service as BLEClientBinder).service
            clientService?.setClientListener(object : BLEClientListener {
                override fun onResult(result: CommonMsg) {
                    // 如果连接成功，更新连接的设备
                    if (result.msgType == BtConstants.CONNECT_SUCCESS) {
                        curConnectMac = result.msg
                    } else if (result.msgType == BtConstants.DISCONNECT) {
                        curConnectMac = ""
                    }
                    clientListener?.onResult(result)
                }

                override fun onNotifyMsgReceive(msg: ByteArray) {
                    clientListener?.onNotifyMsgReceive(msg)
                }
            })
        }

        override fun onServiceDisconnected(name: ComponentName) {
            clientService = null
            clientListener?.onResult(CommonMsg(BtConstants.DISCONNECT, "disconnect from server"))
        }
    }

    /**
     * 扫描蓝牙设备
     *
     * @param btType 蓝牙类型
     */
    fun searchBtDevice(btType: BLUETOOTH_TYPE) {
        if (btType === BLUETOOTH_TYPE.CLASSIC) {
            val mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
            if (mBluetoothAdapter != null) {
                if (mBluetoothAdapter.isDiscovering) {
                    d(TAG, "bt is discovering, cancel")
                    mBluetoothAdapter.cancelDiscovery()
                }
                d(TAG, "bt search start")
                val startResult = mBluetoothAdapter.startDiscovery()
                d(TAG, "start search = $startResult")
            }
        } else if (btType === BLUETOOTH_TYPE.BLE) {
            d(TAG, "ble search start")
            mBtClient!!.search(3000, true)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Observer<BluetoothDevice> {
                    override fun onSubscribe(d: Disposable) {}
                    override fun onNext(bleDevice: BluetoothDevice) {
                        d(TAG, "ble onScanResult")
                    }

                    override fun onError(e: Throwable) {
                        d(TAG, "ble onScanFailed")
                    }

                    override fun onComplete() {}
                })
        }
    }

    /**
     * 连接设备（BLE的连接方式）
     *
     * @param mac MAC地址
     */
    fun connect(mac: String) {
        if (clientService == null) {
            e(TAG, "writeMsg pls init first")
        } else {
            clientService!!.connect(mac, true)
        }
    }

    /**
     * 连接设备（BLE的连接方式）
     *
     * @param mac MAC地址
     */
    fun connect(mac: String, enableNotify: Boolean) {
        if (clientService == null) {
            e(TAG, "writeMsg pls init first")
        } else {
            clientService!!.connect(mac, enableNotify)
        }
    }

    /**
     * 传输内容
     *
     * @param msg 传输的内容
     */
    fun writeMsg(msg: String) {
        d(TAG, "writeMsg $msg")
        write(msg.toByteArray(curCharset))
    }

    /**
     * 传输内容
     *
     * @param msg 传输的内容
     */
    fun write(msg: ByteArray) {
        if (clientService == null) {
            e(TAG, "writeMsg pls init first")
        } else {
            clientService!!.write(msg)
        }
    }

    /**
     * 获取已配对的设备
     */
    fun getBoundDevices(): Set<BluetoothDevice>? {
        return mBtClient?.getBondedDevices()
    }

    /**
     * 检查权限是否具备
     *
     * @param context 上下文 activity级
     * @param requestCode 请求权限CODE
     */
    fun btPermissionCheck(context: Activity, requestCode: Int) {
        // 蓝牙6.0之后如果需要扫描需要添加获取位置权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(
                    context,
                    Manifest.permission.ACCESS_FINE_LOCATION
                ) != PackageManager.PERMISSION_GRANTED
                || checkSelfPermission(
                    context,
                    Manifest.permission.ACCESS_COARSE_LOCATION
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                context.requestPermissions(
                    arrayOf(
                        Manifest.permission.ACCESS_COARSE_LOCATION,
                        Manifest.permission.ACCESS_FINE_LOCATION
                    ),
                    requestCode
                )
            }
        }
    }

    /**
     * 向远端发送通知
     *
     * @param msg 通知内容
     */
    fun sendNotify(msg: String) {
        d(TAG, "send notify : $msg")
        sendNotify(msg.toByteArray(curCharset))
    }

    /**
     * 向远端发送通知
     *
     * @param msg 通知内容
     */
    fun sendNotify(msg: ByteArray) {
        serverService?.sendNotify(msg)
    }

    /**
     * 释放链接
     */
    fun release(context: Context?) {
        if (isBindServer.get()) {
            context?.unbindService(receiverConn)
            isBindServer.set(false)
        }
        if (isBindClient.get()) {
            context?.unbindService(clientConn)
            isBindClient.set(false)
        }
    }
}