package com.device.comm.mylibrary.NativeDevice;

import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.util.Log;

import com.device.comm.mylibrary.BLEDeviceService;
import com.device.comm.mylibrary.BleDevice;
import com.device.comm.mylibrary.BleDeviceConnect;
import com.device.comm.mylibrary.BleDeviceManager;
import com.device.comm.mylibrary.RNLog;
import com.device.comm.mylibrary.UpdateLoop;

import java.util.UUID;

/**
 * Created by lvwang2002 on 2017/6/13.
 */

public class BleNativeBeneCheckerDevice extends BleNativeDevice {
    private String TAG ="RN_BLE_BENE_CHECKER";

    public static final String UUID_BTLE_SERVICE = "00001000-0000-1000-8000-00805f9b34fb";
    public static final String UUID_BTLE_SEND = "00001001-0000-1000-8000-00805f9b34fb";
    public static final String UUID_BTLE_RECEIVE = "00001002-0000-1000-8000-00805f9b34fb";
    private String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";


    BleDevice mDevice = null;
    BleDeviceManager mDeviceManager = null;

    public BleNativeBeneCheckerDevice(BleDevice device, BleDeviceManager deviceManager){
        mDevice = device;
        mDeviceManager = deviceManager;

    }


    @Override
    public String getNotifyCharacteristicUUID() {
        return UUID_BTLE_RECEIVE;
    }

    @Override
    public String getDeviceServiceUUID(){
        return  UUID_BTLE_SERVICE;
    }

    private boolean postNeeded() {
        return mDeviceManager.getUpdateLoop().postNeeded();
    }

    private void post(final Runnable runnable) {
        final UpdateLoop updateLoop = mDeviceManager.getUpdateLoop();

        updateLoop.postIfNeeded(runnable);
    }

    private boolean postMainThreadNeeded() {
        return mDeviceManager.getMainUpdateLoop().postNeeded();
    }

    private void postMainThread(final Runnable runnable) {
        final UpdateLoop updateLoop = mDeviceManager.getMainUpdateLoop();

        updateLoop.postIfNeeded(runnable);
    }



    BleNativeBeneCheckerCallback mDeviceCallback = null;
    public interface BleNativeBeneCheckerCallback extends BleNativeDeviceCallback{
        public void onResult(BleDevice device, GlucoseData data,String type);

    }

    @Override
    public void  setNativeDeviceCallback(BleNativeDeviceCallback deviceCallback){
        RNLog.d(TAG,"set native callback");
        mDeviceCallback =  (BleNativeBeneCheckerCallback)deviceCallback;
    }


    BluetoothGattCharacteristic mNotifyCharacteristic = null;
    BluetoothGattService mDeviceService = null;
    BluetoothGattCharacteristic mGattCharacteristicTrans = null;
    @Override
    public void onServicesDiscovered_mainThread(final BluetoothGatt gatt, final int gattStatus) {
        Log.d(TAG,"找到服务,开始处理");

        if( gattStatus == BluetoothGatt.GATT_SUCCESS ) {

            mDeviceService = gatt.getService(UUID.fromString(UUID_BTLE_SERVICE));
            if(mDeviceService == null){
                mDeviceManager.uhOh(mDevice,"not get device server");
                return;
            }

            mNotifyCharacteristic = mDeviceService.getCharacteristic(UUID.fromString(UUID_BTLE_RECEIVE));
            if(mNotifyCharacteristic == null){
                mDeviceManager.uhOh(mDevice,"not get device Characteristic");
                return;
            }

            mGattCharacteristicTrans = mDeviceService.getCharacteristic(UUID.fromString(UUID_BTLE_SEND));
            if(mNotifyCharacteristic == null){
                mDeviceManager.uhOh(mDevice,"not get send device Characteristic");
                return;
            }
            mGattCharacteristicTrans.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);



            if( postNeeded() ) {
                post(new Runnable() {
                    @Override
                    public void run() {
                        enableNotification(gatt,true,mNotifyCharacteristic);
                    }
                });
            } else {
                enableNotification(gatt,true,mNotifyCharacteristic);
            }


        } else {
            mDeviceManager.uhOh(mDevice,"service status error:"+gattStatus);
        }

    }

    private void enableNotification(final BluetoothGatt gatt,final boolean enable,final BluetoothGattCharacteristic characteristic) {
        if (gatt == null){
            Log.e(TAG,"gatt 为空");
            return;
        }

        if (!(gatt.setCharacteristicNotification(characteristic, enable))){
            Log.e(TAG,"设置Gatt失败");
            mDeviceManager.uhOh(mDevice,"set gatt notify error");
            return;
        }

        BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID
                .fromString(CLIENT_CHARACTERISTIC_CONFIG));
        if (clientConfig == null){
            Log.e(TAG,"clientConfig为空,但好像也不是特别影响");
            return;
        }
        byte[] b = {
                (byte) 0x00, (byte) 0x01
        };
        try{
            clientConfig.setValue(b);
        }catch (Exception e) {
            mDeviceManager.uhOh(mDevice,"null exception");
            return;
        }

        if (enable) {
            Log.i(TAG, "enable notification");
            clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        } else {
            Log.i(TAG, "disable notification");
            clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
        }

        if(!gatt.writeDescriptor(clientConfig)){
            Log.e(TAG,"write descriptor error");

            mDeviceManager.uhOh(mDevice,"write descriptor error");
            return;
        };

    }

    private void sendData(byte[] data) {

        if (data != null && data.length > 0 && data.length < 21) {
            if (mGattCharacteristicTrans.setValue(data)
                    && mDevice.getDeviceConnect().getGatt().writeCharacteristic(mGattCharacteristicTrans)) {
                Log.d(TAG, "send data OK");
            }else{
                Log.d(TAG,"数据长度不在指定范围内");
            }
        }
    }

    /** 接收并处理数据  */
    @Override
    public void receiveData(BluetoothGattCharacteristic characteristic){
        final byte[] data = characteristic.getValue();
        RNLog.d(TAG,BleNativeDevice.Bytes2HexString(data,0,data.length));

        if(!checkedCommandIntegrity(data)){
            RNLog.d(TAG,"完整性检测失败");
            return;
        }

        if(isRepeatData(data)){
            RNLog.d(TAG,"重复数据");
            return;
        }

        mLastData = data;

        RNLog.d(TAG,"完整性检测成功");
        final byte[] validData = ByteUtil.getByteArr(data,4,20);
        RNLog.d(TAG,BleNativeDevice.Bytes2HexString(validData,0,validData.length));

        executeCommand(validData);
    }

    public   boolean checkedCommandIntegrity(byte[] b){
        //长度检测
        if(b.length<20){
            return false;
        }

        return true;
    }

    final static int CMD_GLUCOSE_RESULT = 0x41;
    final static int CMD_CHO_RESULT = 0x61;
    final static int CMD_ACID_RESULT = 0x51; //0x51
    final static int CMD_RCV_ERROR = 0xd0;


    private void executeCommand(byte[] data){
        int command = (data[0]&0x0ff);
        switch (command){
            case CMD_GLUCOSE_RESULT:{
                RNLog.d(TAG,"rcv glucose");
                rcvGlucoseData(data);
            }
            break;

            case  CMD_ACID_RESULT:{
                RNLog.d(TAG,"rcv acid");

                rcvADIDData(data);

            }
            break;

            case CMD_CHO_RESULT:{
                RNLog.d(TAG,"rcv cho");
            }
            break;

            case CMD_RCV_ERROR:{
                RNLog.d(TAG,"rcv error");
            }

            default:{
                RNLog.d(TAG,"no execute");
            }
        }
    }


    private byte[] mLastTimeData = null;
    private void rcvADIDData(byte[] data){
        //直接提取时间数据和测量值
        byte[] timeData = ByteUtil.getByteArr(data,8,13);
        byte[] valueData = ByteUtil.getByteArr(data,13,15);
        RNLog.d(TAG,"time:"+Bytes2HexString(timeData,0,timeData.length));
        RNLog.d(TAG,"value:"+Bytes2HexString(valueData,0,valueData.length));


        GlucoseData gData = data2Glucose(data);

        mDeviceCallback.onResult(mDevice,gData,"adid");


        try{
            Thread.sleep(500);
        }catch (InterruptedException error){
            error.printStackTrace();
        }

        sendRespondData();
    }
    private void rcvGlucoseData(byte[] data){
        //直接提取时间数据和测量值
        byte[] timeData = ByteUtil.getByteArr(data,8,13);
        byte[] valueData = ByteUtil.getByteArr(data,13,15);
        RNLog.d(TAG,"time:"+Bytes2HexString(timeData,0,timeData.length));
        RNLog.d(TAG,"value:"+Bytes2HexString(valueData,0,valueData.length));


        GlucoseData gData = data2Glucose(data);

        mDeviceCallback.onResult(mDevice,gData,"glucose");


        try{
            Thread.sleep(500);
        }catch (InterruptedException error){
            error.printStackTrace();
        }

        sendRespondData();
    }

    /** 发送响应数据 */
    private void sendRespondData(){
        byte[] data = {
                (byte)0x24,(byte)0x50,(byte) 0x43,(byte) 0x4C,
                (byte)0x01,(byte)0x00,
                (byte)0x00,(byte)0x00,
                (byte)0x00,(byte)0x00,
                (byte)0x0e
        };
        sendData(data);
    }



    /** 判断是否是重复数据 */
    private boolean isRepeatData(byte[] data){
        if(mLastData == null){
            return  false;
        }

        if(data.length != mLastData.length){
            return false;
        }

        for(int i=0;i<data.length;i++){
            byte itemA = data[i];
            byte itemB = mLastData[i];
            if(itemA != itemB){
                return false;
            }
        }

        return  true;
    }




    public static boolean checkedCommandCRC(byte[] b){
        byte[] a = new byte[10];
        System.arraycopy(b, 4, a, 0, 10);
        int crcValue = BleDeviceCRC.calcCrc16(a,0,8,65535);
        long high = ((long) (b[13] & 0xFF))*256;
        long result = high + (long)(b[12] & 0xFF);
        return result == crcValue;
    }

    private static int queId = -1;
    /** 校验是否是重复指令 */
    public static boolean checkedRepeatCommand(byte[] b){
        int m = (b[2]&0xff);
        if(m == queId){
            return true;
        }
        //2.将该条命令的顺序id写入缓存
        queId = m;

        //4.返回false.
        return false;
    }

    private  byte[] mLastData = null;

    private boolean checkedTimeRepeatCommand(byte[] b){
        if(mLastData == null){
            mLastData = b;
            return false;
        }


        if(mLastData.length<10){
            return  false;
        }

        if(b[6] == mLastData[6] &&
                b[4] == mLastData[4] &&
                b[5] == mLastData[5] &&
                b[7] == mLastData[7] &&
                b[8] == mLastData[8] &&
                b[9] == mLastData[9]){
            return true;
        }

        mLastData = b;
        return false;
    }

    public GlucoseData data2Glucose(byte[] data){
        Log.d(TAG, "data2Glucose: 原始data"+data);
        GlucoseData glucoseData = new GlucoseData();
        glucoseData.setYear(2000+(data[8] & 0xff));
        glucoseData.setMonth(data[9] & 0xff);
        glucoseData.setDay(data[10] & 0xff);
        glucoseData.setHour(data[11] & 0xff);
        glucoseData.setMinute(data[12] & 0xff);
        glucoseData.setGlucose((data[13]&0xff) + 256*(data[14]&0xff-128));
        Log.d(TAG, "data2Glucose: "+glucoseData);
        return glucoseData;
    }

    @Override
    public String getDeviceDisplayName(){
        return "BeneCheck";
    }

    @Override
    public boolean disableNotifications() {
        BleDeviceConnect connect  = mDevice.getDeviceConnect();
        if(connect == null){
            return false;
        }

        BluetoothGatt gatt = connect.getGatt();
        if (gatt == null || mNotifyCharacteristic == null)
            return false;

        if (!(gatt.setCharacteristicNotification(mNotifyCharacteristic, false)))
            return false;

        BluetoothGattDescriptor clientConfig = mNotifyCharacteristic.getDescriptor(UUID.fromString(this.CLIENT_CHARACTERISTIC_CONFIG));
        if (clientConfig == null)
            return false;

        Log.i(TAG, "disable notification");
        clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);

        return gatt.writeDescriptor(clientConfig);
    }

}
