package com.common.bluetooth.service;

import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.Nullable;

import com.common.bluetooth.BtConstants;
import com.common.bluetooth.callback.BleMsgReceiverListener;

import java.nio.charset.StandardCharsets;

/**
 * BLE接收服务
 *
 * @author wangym
 * @since 2021-10-29
 */
public class BLEReceiveService extends Service {
    private static final String TAG = "BLEReceiveService";
    /**
     * 蓝牙管理
     */
    private BluetoothManager bluetoothManager;
    /**
     * GATT 服务
     */
    private BluetoothGattServer gattServer;
    /**
     * 开启通知的属性
     */
    private BluetoothGattCharacteristic mNotify;
    /**
     * 蓝牙消息接收监听
     */
    private BleMsgReceiverListener receiverListener;
    /**
     * 远端设备
     */
    private BluetoothDevice remoteDevice;

    private final BluetoothGattServerCallback serverCallback = new BluetoothGattServerCallback() {
        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
            super.onConnectionStateChange(device, status, newState);
            Log.d(TAG,
                    "BluetoothGattServerCallback onConnectionStateChange status: " + status + " newState: " + newState);
        }

        @Override
        public void onServiceAdded(int status, BluetoothGattService service) {
            super.onServiceAdded(status, service);
            Log.d(TAG,
                    "BluetoothGattServerCallback onServiceAdded status: " + status + " service: " + service.getUuid().toString());
        }

        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
                                                BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
            Log.d(TAG,
                    "BluetoothGattServerCallback onCharacteristicReadRequest characteristic: " + characteristic.getUuid().toString());
            gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
        }

        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
                                                 BluetoothGattCharacteristic characteristic, boolean preparedWrite,
                                                 boolean responseNeeded, int offset, byte[] value) {
            super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset,
                    value);
            Log.d(TAG,
                    "BluetoothGattServerCallback onCharacteristicWriteRequest characteristic: " + characteristic.getUuid().toString());
            Log.d(TAG,
                    "BluetoothGattServerCallback onCharacteristicWriteRequest value: " + new String(value));
            gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
            // 处理响应内容
            onResponseToClient(value, device, requestId);
        }

        @Override
        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset,
                                            BluetoothGattDescriptor descriptor) {
            super.onDescriptorReadRequest(device, requestId, offset, descriptor);
            Log.d(TAG, "onDescriptorReadRequest device = " + device.getAddress());
            gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
        }

        @Override
        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor,
                                             boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
            String valueStr = new String(value);
            Log.d(TAG, "onDescriptorWriteRequest device = " + device.getAddress());
            Log.d(TAG, "onDescriptorWriteRequest valueStr = " + valueStr);
            gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
            // 判断是否打开通知
            if (new String(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE).equals(valueStr)) {
                Log.d(TAG, "onDescriptorWriteRequest open notify");
                mNotify = descriptor.getCharacteristic();
                remoteDevice = device;
            } else {
                mNotify = null;
                remoteDevice = null;
            }
        }

        @Override
        public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
            super.onExecuteWrite(device, requestId, execute);
            Log.d(TAG, "onExecuteWrite device = " + device.getAddress());
        }

        @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
            super.onNotificationSent(device, status);
            Log.d(TAG, "onNotificationSent device = " + device.getAddress());
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();

        bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        if (bluetoothManager != null) {
            Log.i(TAG, "initialize BluetoothManager");
            initServer();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new ReceiverBinder();
    }

    public class ReceiverBinder extends Binder {
        public BLEReceiveService getService() {
            return BLEReceiveService.this;
        }
    }

    public void setMsgReceiveListener(BleMsgReceiverListener listener) {
        receiverListener = listener;
    }

    /**
     * 建立服务
     */
    private void initServer() {
        AdvertiseSettings settings = new AdvertiseSettings.Builder()
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)// 广播的模式 低功耗 平衡 低延迟
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
                .setConnectable(true)
                .build();

        AdvertiseData advertiseData = new AdvertiseData.Builder().build();

        //通过UUID_SERVICE构建
        AdvertiseData scanResponseData = new AdvertiseData.Builder()
                .addServiceUuid(new ParcelUuid(BtConstants.INSTANCE.getUUID_SERVICE()))
                .build();

        //广播创建成功之后的回调
        AdvertiseCallback callback = new AdvertiseCallback() {
            @Override
            public void onStartSuccess(AdvertiseSettings settingsInEffect) {
                Log.d(TAG, "BLE advertisement added successfully");
                //初始化服务
                initServices(BLEReceiveService.this);
            }

            @Override
            public void onStartFailure(int errorCode) {
                Log.e(TAG, "Failed to add BLE advertisement, reason: " + errorCode);
            }
        };

        //部分设备不支持Ble中心
        BluetoothLeAdvertiser bluetoothLeAdvertiser = bluetoothManager.getAdapter().getBluetoothLeAdvertiser();
        if (bluetoothLeAdvertiser == null) {
            Log.i(TAG, "BluetoothLeAdvertiser为null");
            return;
        }

        //开始广播
        bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, scanResponseData, callback);
    }

    private void initServices(Context context) {
        // 创建gattServer服务器
        gattServer = bluetoothManager.openGattServer(context, serverCallback);

        // 创建指定的UUID的服务
        BluetoothGattService service = new BluetoothGattService(BtConstants.INSTANCE.getUUID_SERVICE(),
                BluetoothGattService.SERVICE_TYPE_PRIMARY);

        //添加指定UUID的可读characteristic
        BluetoothGattCharacteristic characteristicNotify = new BluetoothGattCharacteristic(
                BtConstants.INSTANCE.getUUID_CHARACTERISTIC_NOTIFY(),
                BluetoothGattCharacteristic.PROPERTY_WRITE |
                        BluetoothGattCharacteristic.PROPERTY_READ |
                        BluetoothGattCharacteristic.PROPERTY_NOTIFY,
                BluetoothGattCharacteristic.PERMISSION_READ);
        //添加可读characteristic的descriptor
        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(BtConstants.INSTANCE.getUUID_DESCRIPTOR(),
                BluetoothGattCharacteristic.PERMISSION_WRITE);
        characteristicNotify.addDescriptor(descriptor);
        service.addCharacteristic(characteristicNotify);

        //添加指定UUID的可写characteristic
        BluetoothGattCharacteristic characteristicWrite = new BluetoothGattCharacteristic(
                BtConstants.INSTANCE.getUUID_CHARACTERISTIC_WRITE(),
                BluetoothGattCharacteristic.PROPERTY_WRITE |
                        BluetoothGattCharacteristic.PROPERTY_READ |
                        BluetoothGattCharacteristic.PROPERTY_NOTIFY,
                BluetoothGattCharacteristic.PERMISSION_WRITE);
        service.addCharacteristic(characteristicWrite);

        gattServer.addService(service);
    }

    /**
     * 4.处理响应内容
     */
    private void onResponseToClient(byte[] requestByte, BluetoothDevice device, int requestId) {
        Log.d(TAG, String.format("onResponseToClient：device name = %s, address = %s", device.getName(),
                device.getAddress()));
        Log.d(TAG, String.format("onResponseToClient：requestId = %s", requestId));

        String str = new String(requestByte);
        Log.d(TAG, "收到：" + str);
        sendNotify(requestByte);
        Log.d(TAG, "响应：" + str);

        if (receiverListener != null) {
            receiverListener.onMsgReceive(requestByte);
        }
    }

    /**
     * 向客户端发送通知
     *
     * @param msg 消息
     */
    public void sendNotify(byte[] msg) {
        Log.i(TAG, "sendNotify msg = " + new String(msg));
        if (mNotify != null && gattServer != null && msg != null) {
            Log.i(TAG, "---send notify start---");
            mNotify.setValue(msg);
            gattServer.notifyCharacteristicChanged(remoteDevice, mNotify, false);
            Log.i(TAG, "---send notify end---");
        } else {
            Log.e(TAG, "got notify null");
        }
    }

    @Override
    public boolean onUnbind(Intent intent) {
        mNotify = null;
        return super.onUnbind(intent);
    }
}
