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.*
import androidx.core.content.ContextCompat.checkSelfPermission
import com.common.bluetooth.BtConstants.BLUETOOTH_TYPE
import com.common.bluetooth.service.ble.BluetoothClientBLEAdapter
import com.common.bluetooth.bean.CommonMsg
import com.common.bluetooth.callback.BLEClientListener
import com.common.bluetooth.callback.BtMsgListener
import com.common.bluetooth.callback.BtServiceListener
import com.common.bluetooth.callback.MsgReceiverListener
import com.common.bluetooth.interfaces.IBluetoothClient
import com.common.bluetooth.service.ble.BLEClientService
import com.common.bluetooth.service.ble.BLEClientService.BLEClientBinder
import com.common.bluetooth.service.ble.BLEReceiveService
import com.common.bluetooth.service.ble.BLEReceiveService.ReceiverBinder
import com.common.bluetooth.service.ble.BluetoothLeClient
import com.common.bluetooth.service.bt.BTCClientService
import com.common.bluetooth.service.bt.BTCReceiverService
import com.common.bluetooth.service.bt.BluetoothClassicClient
import com.common.bluetooth.service.bt.BluetoothClientClassicAdapter
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

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

    /**
     * 经典蓝牙客户端服务
     */
    private var classicClientService: BTCClientService? = null

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

    /**
     * 经典蓝牙服务端服务
     */
    private var classicServerService: BTCReceiverService? = null

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

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

    /**
     * 蓝牙服务链接监听
     */
    var btServiceListener: BtServiceListener? = null

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

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

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

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

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

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

    /**
     * 初始化蓝牙服务端模块
     */
    fun initServer(context: Context, btType: BLUETOOTH_TYPE) {
        if (btType == BLUETOOTH_TYPE.BLE) {
            mBtClient = BluetoothClientBLEAdapter(
                BluetoothLeClient.getInstance(context)
            )
            initBleReceiverService(context)
        } else if (btType == BLUETOOTH_TYPE.CLASSIC) {
            mBtClient = BluetoothClientClassicAdapter(BluetoothClassicClient(context))
            initClassicReceiverService(context)
        }
        mBtClient!!.checkBluetoothDevice(btType)

    }

    /**
     * 初始化蓝牙客户端模块
     */
    fun initClient(context: Activity, btType: BLUETOOTH_TYPE) {
        if (btType == BLUETOOTH_TYPE.BLE) {
            mBtClient = BluetoothClientBLEAdapter(
                BluetoothLeClient.getInstance(context)
            )
            initBleClientService(context)
        } else if (btType == BLUETOOTH_TYPE.CLASSIC) {
            mBtClient = BluetoothClientClassicAdapter(
                BluetoothClassicClient(context)
            )
            initClassicClientService(context)
        }
        mBtClient!!.checkBluetoothDevice(btType)
    }

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

    private fun initClassicReceiverService(context: Context) {
        val intent = Intent(context, BTCReceiverService::class.java)
        // 标志位BIND_AUTO_CREATE是的服务中onCreate得到执行,onStartCommand不会执行
        context.bindService(intent, classicReceiverConn, Context.BIND_AUTO_CREATE)
        isBindClassicServer.set(true)
    }

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

    private fun initClassicClientService(context: Context) {
        val intent = Intent(context, BTCClientService::class.java)
        // 标志位BIND_AUTO_CREATE是的服务中onCreate得到执行,onStartCommand不会执行
        context.bindService(intent, classicClientConn, Context.BIND_AUTO_CREATE)
        isBindClassicClient.set(true)
    }

    private val bleReceiverConn: ServiceConnection by lazy {
        object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName, service: IBinder) {
                serverService = (service as ReceiverBinder).service
                serverService?.setMsgReceiveListener(object : MsgReceiverListener {
                    override fun onMsgReceive(msg: ByteArray) {
                        msgReceiverListener?.onMsgReceive(msg)
                    }
                })
                btServiceListener?.onServiceReady()
            }

            override fun onServiceDisconnected(name: ComponentName) {
                serverService = null
                btServiceListener?.onServiceDisConnected()
            }
        }
    }

    private val classicReceiverConn: ServiceConnection by lazy {
        object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName, service: IBinder) {
                classicServerService = (service as BTCReceiverService.ClassicReceiverBinder).service
                classicServerService?.setMsgReceiveListener(object : BtMsgListener() {
                    override fun socketNotify(state: Int, msg: String) {
                        msgReceiverListener?.onMsgReceive(msg.toByteArray())
                    }
                })
                btServiceListener?.onServiceReady()
            }

            override fun onServiceDisconnected(name: ComponentName) {
                classicServerService = null
                btServiceListener?.onServiceDisConnected()
            }
        }
    }

    private val bleClientConn: ServiceConnection by lazy {
        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)
                    }
                })
                btServiceListener?.onServiceReady()
            }

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

    private val classicClientConn: ServiceConnection by lazy {
        object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName, service: IBinder) {
                classicClientService = (service as BTCClientService.ClassicClientBinder).service
                classicClientService?.setMsgReceiveListener(object : BtMsgListener() {
                    override fun socketNotify(state: Int, msg: String) {
                        when (state) {
                            CONNECTED -> {
                                curConnectMac = msg
                                clientListener?.onResult(
                                    CommonMsg(
                                        BtConstants.CONNECT_SUCCESS,
                                        msg
                                    )
                                )
                            }
                            DISCONNECTED -> {
                                curConnectMac = ""
                                clientListener?.onResult(CommonMsg(BtConstants.DISCONNECT, msg))
                            }
                            MSG -> {
                                clientListener?.onNotifyMsgReceive(msg.toByteArray())
                            }
                            else -> {
                                e(TAG, "got error state:$state")
                            }
                        }
                    }
                })
                btServiceListener?.onServiceReady()
            }

            override fun onServiceDisconnected(name: ComponentName) {
                classicClientService = null
                btServiceListener?.onServiceDisConnected()
            }
        }
    }

    /**
     * 扫描蓝牙设备
     *
     * @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) {
            clientService!!.connect(mac, true)
        } else {
            w(TAG, "init clientService first")
        }

        if (classicClientService != null) {
            classicClientService!!.connect(mac)
        } else {
            w(TAG, "init classicClientService first")
        }
    }

    /**
     * 连接设备（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) {
            clientService!!.write(msg)
        }

        if (classicClientService != null) {
            classicClientService!!.write(msg)
        }

        if (classicServerService != null) {
            classicServerService!!.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)
        classicServerService?.write(msg)
    }

    /**
     * 释放链接
     */
    fun release(context: Context?) {
        if (isBindBleServer.get()) {
            context?.unbindService(bleReceiverConn)
            isBindBleServer.set(false)
        }
        if (isBindClassicServer.get()) {
            context?.unbindService(classicReceiverConn)
            isBindClassicServer.set(false)
        }
        if (isBindBleClient.get()) {
            context?.unbindService(bleClientConn)
            isBindBleClient.set(false)
        }
        if (isBindClassicClient.get()) {
            context?.unbindService(classicClientConn)
            isBindClassicServer.set(false)
        }
    }
}