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.BleDevice;
import com.device.comm.mylibrary.BleDeviceConnect;
import com.device.comm.mylibrary.BleDeviceManager;
import com.device.comm.mylibrary.NativeDevice.BleNativeDevice;

import com.device.comm.mylibrary.RNLog;
import com.device.comm.mylibrary.UpdateLoop;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Created by lvwang2002 on 16/1/27.
 */
public class BleNativeEnuoBPDevice extends BleNativeDevice {
    private String TAG ="RN_BLE_PG_BP";

    public static final String UUID_BTLE_SERVICE = "0000fc00-0000-1000-8000-00805f9b34fb";
    public static final String UUID_BTLE_SEND = "0000fca0-0000-1000-8000-00805f9b34fb";
    public static final String UUID_BTLE_RECEIVE = "0000fca1-0000-1000-8000-00805f9b34fb";
    public static final String UUID_BTLE_SETTING_CODE = "0000fca2-0000-1000-8000-00805f9b34fb";
    private String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";


    BleDevice mDevice = null;
    BleDeviceManager mDeviceManager = null;
    boolean mIsReceivedState = false;
    boolean mIsAllowSendBattery = false;

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

    }

    public enum BPStatus{
        BPStatusStartTest,
        BPStatusStopTest,BPStatusStartZero,BPStatusStopZero
    }


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

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

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

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

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

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

        updateLoop.postIfNeeded(runnable);
    }

    com.device.comm.mylibrary.NativeDevice.BleNativeRBPDeviceCallback mDeviceCallback = null;
    public interface BleNativeRBPDeviceCallback extends BleNativeDeviceCallback{
        public void onStartTest(BleDevice device);
        public void onStopZero(BleDevice device);
        public void onResult(BleDevice device, Map<String, String> result);
        public void onProgressStatus(BleDevice device, BPStatus status);
        public void onProgressValue(BleDevice device, Map<String, String> value);
        public void onError(BleDevice device, Map<String, String> error);
        public void onStopTest(BleDevice device);
        public void onPower(BleDevice device,int power);
        public void onDeviceShutDown(BleDevice device);
        public void onCheckConnectFinish(BleDevice device,boolean isSuc);
    }
    @Override
    public void  setNativeDeviceCallback(BleNativeDeviceCallback deviceCallback){
        mDeviceCallback = (com.device.comm.mylibrary.NativeDevice.BleNativeRBPDeviceCallback) deviceCallback;
    }

    BluetoothGattCharacteristic mNotifyCharacteristic = null;
    BluetoothGattService mDeviceService = null;
    BluetoothGattCharacteristic mGattCharacteristicTrans = null;
    BluetoothGattCharacteristic mGattCharacteristicSettingCode = null;
    @Override
    public void onServicesDiscovered_mainThread(final BluetoothGatt gatt, final int gattStatus) {
        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 (mGattCharacteristicTrans == null) {
                mDeviceManager.uhOh(mDevice, "not get send device Characteristic");
                return;
            }
            mGattCharacteristicTrans.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);

            mGattCharacteristicSettingCode = mDeviceService.getCharacteristic(UUID.fromString(UUID_BTLE_SETTING_CODE));
            if (mGattCharacteristicSettingCode == null) {
                mDeviceManager.uhOh(mDevice, "not get send device Characteristic");
                return;
            }
            mGattCharacteristicSettingCode.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);


            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 synchronized 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;
        }

        postDelay(new Runnable() {
            @Override
            public void run() {
                sendSettingCode();
            }
        },600);
////
////
////
        postDelay(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG,"send status");
                sendStatusConnected();
            }
        },800);
////
        postDelay(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG,"send status");
                sendGetBatteryValue();
            }
        },1000);
//
        postDelay(new Runnable() {
            @Override
            public void run() {
                mIsAllowSendBattery = true;
                 RNLog.d(TAG,"check connect state");
                if(!mIsReceivedState){
                    RNLog.d(TAG,"check error");
//                    mDeviceManager.uhOh(mDevice,"bp error");
                    return;
                }
                RNLog.d(TAG,"check  ok");
                postDelay(new Runnable(){
                    @Override
                    public void run(){
                        if(mDeviceCallback != null){
                            postMainThread(new Runnable() {
                                @Override
                                public void run() {
                                    mDeviceCallback.onCheckConnectFinish(mDevice,mIsReceivedState);
                                }
                            });
                        }
                    }
                }, 1000);
            }
        },1200);


    }

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

    }

    private synchronized void sendData(byte[] data) {
        if(mDevice.getDeviceConnect().getGatt() == null){
            return;
        }

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

    private int BLEPacketSize = 20;
    public synchronized void sendBigData(byte[] data){
        int length = data.length/BLEPacketSize+(data.length%BLEPacketSize>0?1:0);
        RNLog.d(TAG,"data length:"+data.length);
        RNLog.d(TAG,"big data length:"+length);
        for(int i=0;i<length;i++){
            int dataLength = ((i*BLEPacketSize+BLEPacketSize)<data.length)?BLEPacketSize:(data.length-i*BLEPacketSize);
            RNLog.d(TAG,"data length:"+dataLength);
            byte[] sendData = ByteUtil.getByteArr(data,i*BLEPacketSize,i*BLEPacketSize+dataLength);
            RNLog.d(TAG,"send data:"+ Bytes2HexString(sendData,0,sendData.length));
            sendData(sendData);


            try{
                Thread.sleep(100);
            }catch (InterruptedException error){
                RNLog.d(TAG,"error:"+error);
                error.printStackTrace();
            }
        }
    }

    /* 发送设置码 */
    private synchronized void sendSettingCode() {
        if(mDevice == null){
            mDeviceManager.uhOh(mDevice,"error");
            return;
        }

        byte[] data = {(byte) 0xf0, (byte) 0xD2, (byte) 0xA9, (byte) 0xC6, (byte) 0x0F, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x08, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
        Log.i(TAG,""+data.length);
        if (data != null && data.length > 0 && data.length < 21) {
            if (mGattCharacteristicSettingCode.setValue(data)
                    && mDevice.getDeviceConnect().getGatt().writeCharacteristic(mGattCharacteristicSettingCode)) {
                Log.i(TAG, "send data OK");
            }else{
                Log.i(TAG,"数据长度不在指定范围内");
            }
        }
    }

    /** 发送连接状态 */
    private synchronized void sendStatusConnected(){
        byte[] data ={(byte)0x04,(byte)0xa1,(byte)0xa0,(byte)0x45};
        sendData(data);
    }

    /** 开始测量 */
    public synchronized void sendStartTest(){
        byte[] data = {(byte)0x04,(byte)0xa1,(byte)0xa1,(byte)0x46};
        sendData(data);
    }

    /** 停止测量 */
    public  synchronized void sendStopTest(){
        Log.i(TAG,"发送停止测量");
        byte[] data = {(byte)0x04,(byte)0xa1,(byte)0xa2,(byte)0x47};
        sendData(data);
    }

    /** 获取电量 */
    public  synchronized void sendGetBatteryValue(){
        Log.i(TAG,"获取电量");
        byte[] data = {(byte)0x04,(byte)0xa1,(byte)0xa5,(byte)0x4a};
        sendData(data);
    }

    /** 获取设备id */
    public synchronized void sendGetDeviceID(){
        Log.i(TAG,"获取DeviceID");
        byte[] data = {(byte)0x04,(byte)0xa1,(byte)0xa4,(byte)0x49};
        sendData(data);
    }

    /** 血压计关机 */
    public synchronized void sendPowerOffDevice(){
        Log.i(TAG,"要求设备关机");
        byte[] data = {(byte)0x04,(byte)0xa1,(byte)0xa6,(byte)0x4b};
        sendData(data);
    }

    /** 设置血压ID */
    public synchronized  void sendSetDeviceID(){
        Log.i(TAG,"设置DeviceID");
        byte[] data = {(byte)0x07,(byte)0xa1,(byte)0xa3,(byte)0x01,(byte)0xff,(byte)0xaa,(byte)0xf5};
        sendData(data);
    }

    /** 查询咨询密码 */
    public synchronized void searchSettingCode(){
        Log.i(TAG,"查询配置码");
        byte[] data = {(byte)0x04,(byte)0x55,(byte)0xaa,(byte)0x03};
        sendData(data);
    }

    /** 设置血压计日期 */
    public synchronized void sendSetDeviceDate(){
        Log.i(TAG,"设置日期");
        byte[] data = {(byte)0x07,(byte)0xa1,(byte)0xa8,(byte)0x0e,(byte)0x0a,(byte)0x08,(byte)0x70};
        sendData(data);
    }

    /** 设置血压时间 */
    public synchronized void sendSetDeviceTime(){
        Log.i(TAG,"设置时间");
        byte[] data = {(byte)0x07,(byte)0xa1,(byte)0xa9,(byte)0x17,(byte)0x2d,(byte)0x08,(byte)0x9d};
        sendData(data);
    }

    /** 读取血糖历史  */
    public synchronized void sendGetHistory(){
        Log.i(TAG,"获取历史数据");

        byte[] data = {(byte)0x04,(byte)0xa1,(byte)0xac,(byte)0x51};
        sendData(data);
    }

    /** 断开蓝牙  */
    public synchronized void sendTurnOffBT(){
        Log.i(TAG,"断开蓝牙");
        byte[] data = {(byte)0x04,(byte)0xa1,(byte)0xad,(byte)0x52};
        sendData(data);
    }

    /** 设置自动测量血压数据 */
    public synchronized void sendSetDyBP(){
        Log.i(TAG,"设置血压");
        byte[] data = {
                (byte)0x15,(byte)0xa1,(byte)0xc0,
                (byte)0x11,(byte)0x09,(byte)0x0c,(byte)0x08,(byte)0x13,(byte)0x00,
                (byte)0x07,(byte)0x1e,(byte)0x15,(byte)0x1e,(byte)0x05,
                (byte)0x15,(byte)0x1e,(byte)0x07,(byte)0x1e,(byte)0x05,
                (byte)0x11,
//                (byte)0xd2
        };
        byte verify = (byte)countVerify(data);
        RNLog.d(TAG,""+countVerify(ByteUtil.getByteArr(data,0,20)));
        byte[] verifyList = {verify};
        data = concat(data,verifyList);

        sendBigData(data);
    }

    private int countVerify(byte[] dataList){
        int verifyData = 0;
        for(byte data:dataList){
            verifyData = verifyData + (data&0xff);
        }
        return verifyData%256;

    }
    public static byte[] concat(byte[] first, byte[] second) {
        byte[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }


    public synchronized void postDelay(Runnable runnable,long delayMillis){
        final UpdateLoop updateLoop = mDeviceManager.getUpdateLoop();
        updateLoop.postDelay(runnable,delayMillis);
    }


    private synchronized void respondBP(){
        Log.i(TAG,"回应动态血压的值");
        byte[] data = {(byte)0x04,(byte)0xa1,(byte)0xc8,(byte)0x6d};
        sendData(data);
    }

    /** 对接收的数据进行处理 */
    private synchronized void handlerReceivedData(byte[] data){
        if(data.length<4){
            return;
        }

        if(data[0] != data.length){
            Log.i(TAG,"指令长度不符");
            return;
        }

        int commandFlag = (int)(data[2] & 0xff);
        switch (commandFlag){
            case 0x55:{
                Log.i(TAG,"配置码:"+data[2]+" "+data[3]);

            }
            break;

            case 0xa0:{
                Log.i(TAG,"接收到连接状态");
            }
            break;

            case 0xb1:{
                //血压计通知开始测量
                Log.i(TAG,"start test");
                if(mDeviceCallback != null){
                    postMainThread(new Runnable() {
                        @Override
                        public void run() {
                            mDeviceCallback.onStartTest(mDevice);
                        }
                    });
                }
            }
            break;
            case 0xb2:{
                //血压计通知测量停止测量
                Log.i(TAG,"stop test");
                if(mDeviceCallback != null){
                    postMainThread(new Runnable() {
                        @Override
                        public void run() {
                            mDeviceCallback.onStopTest(mDevice);
                        }
                    });
                }
            }
            break;
            case 0xb3:{
                //血压计通知正在归零
                Log.i(TAG,"stop test start zero");
            }
            break;
            case 0xb4:{
                //血压计通知归零结束
                Log.i(TAG,"stop test stop zero");
                //血压计通知开始测量
                Log.i(TAG,"start test");
                if(mDeviceCallback != null){
                    postMainThread(new Runnable() {
                        @Override
                        public void run() {
                            mDeviceCallback.onStopZero(mDevice);
                        }
                    });
                }
            }
            break;
            case 0xb5:{
                RNLog.d(TAG,"电池电量:"+(data[3]&0xff));
                mIsReceivedState = true;

                if(!mIsAllowSendBattery){
                    return;
                }

                final int power = (int)(data[3]&0xff);

                if(mDeviceCallback != null){

                    postMainThread(new Runnable() {
                        @Override
                        public void run() {
                            mDeviceCallback.onPower(mDevice,power);
                        }
                    });
                }
            }
            break;

            case 0xb6:{
                Log.i(TAG,"ID号:"+data[3]+data[4]+data[5]);

            }
            break;
            case 0xb7:{
                //血压计发送过程数据
                boolean isHeart = (((data[3]&0xff) & 0b00010000) == 0b00010000);
                int value = (((data[3]&0xff) & 0x0f) & 0xff)*256 + (data[4] & 0xff);
                Log.i(TAG,"blood value:"+value+"  is heart:"+isHeart);

                if(mDeviceCallback != null){
                    final Map<String,String> info = new HashMap<String, String>();
                    info.put("value",""+value);
                    info.put("isHeart",""+isHeart);
                    postMainThread(new Runnable() {
                        @Override
                        public void run() {
                            mDeviceCallback.onProgressValue(mDevice,info);
                        }
                    });
                }

            }
            break;

            case 0xb8:{
                //血压计发送测量结果
                boolean isHeart = (((data[3]&0xff) & 0b10000000) == 0b10000000);
                int sysValue = (((data[3]&0xff) & 0x0f)&0xff)*256 + (data[4]&0xff);
                int diaValue = data[5] & 0xff;
                int pulValue = data[6] & 0xff;
                Log.i(TAG,"dia value:"+diaValue+" sys value:"+sysValue);
                Log.i(TAG,"pul:"+pulValue+"is heart:"+isHeart);

                if(mDeviceCallback != null){
                    final Map<String,String> info = new HashMap<String, String>();
                    info.put("dia",""+diaValue);
                    info.put("sys",""+sysValue);
                    info.put("pul",""+pulValue);
                    info.put("isHeart",""+isHeart);
                    postMainThread(new Runnable() {
                        @Override
                        public void run() {
                            mDeviceCallback.onResult(mDevice,info);
                        }
                    });

                }

            }
            break;
            case 0xb9:{
                //血压计发送测量错误信息
                Log.i(TAG,"error:"+data[3]);
//                List<String> contents = new ArrayList<String>();
//                contents.add();
                String[] errorTypes = {"测量不到有效脉搏",
                        "气袋没绑好",
                        "测量结果数值有误",
                        "进入超压保护",
                        "测量中干预过多"};



                if(mDeviceCallback != null){
                    final Map<String,String> info = new HashMap<String, String>();
                    info.put("errorCode",""+""+""+data[3]);
                    info.put("error",""+""+""+errorTypes[data[3]]);

                    postMainThread(new Runnable() {
                        @Override
                        public void run() {
                            mDeviceCallback.onError(mDevice,info);
                        }
                    });
                }

            }
            break;

            case 0xba:{
                //血压计发送关机信号
                Log.i(TAG,"血压计发送关机信号");
                if(mDeviceCallback != null){
                    postMainThread(new Runnable() {
                        @Override
                        public void run() {
                            mDeviceCallback.onDeviceShutDown(mDevice);;
                        }
                    });
                }
            }
            break;

            case 0xbb:{
                //血压计发送低电信号
                Log.i(TAG,"血压计发送低电信号");
                if(mDeviceCallback != null){
                    final Map<String,String> info = new HashMap<String, String>();
                    info.put("errorCode",""+""+""+101);
                    info.put("error",""+""+""+"电量不足，请更换电池");

                    postMainThread(new Runnable() {
                        @Override
                        public void run() {
                            mDeviceCallback.onError(mDevice,info);
                        }
                    });
                }
            }
            break;

            case 0xbc:{
                //接收时间设置
                Log.i(TAG,"血压计时间设置成功");
            }
            break;
        }
    }

    @Override
    public String getDeviceDisplayName(){
        return "攀高电子血压计";
    }

    @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);
    }
}
