package ugen.fy.plugin;

import android.app.Application;
import android.content.Context;
import android.text.TextUtils;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.Nullable;

import com.alibaba.sdk.android.openaccount.ConfigManager;
import com.alibaba.sdk.android.openaccount.OpenAccountSDK;
import com.alibaba.sdk.android.openaccount.OpenAccountService;
import com.alibaba.sdk.android.openaccount.callback.InitResultCallback;
import com.alibaba.wireless.security.jaq.JAQException;
import com.alibaba.wireless.security.jaq.SecurityInit;
import com.aliyun.alink.business.devicecenter.api.add.AddDeviceBiz;
import com.aliyun.alink.business.devicecenter.api.add.DeviceInfo;
import com.aliyun.alink.business.devicecenter.api.add.IAddDeviceListener;
import com.aliyun.alink.business.devicecenter.api.add.LinkType;
import com.aliyun.alink.business.devicecenter.api.add.ProvisionStatus;
import com.aliyun.alink.business.devicecenter.api.add.RegionInfo;
import com.aliyun.alink.business.devicecenter.api.discovery.DiscoveryType;
import com.aliyun.alink.business.devicecenter.api.discovery.IDeviceDiscoveryListener;
import com.aliyun.alink.business.devicecenter.api.discovery.IOnDeviceTokenGetListener;
import com.aliyun.alink.business.devicecenter.api.discovery.LocalDeviceMgr;
import com.aliyun.alink.business.devicecenter.base.DCErrorCode;
import com.aliyun.alink.linksdk.channel.core.base.AError;
import com.aliyun.alink.linksdk.channel.mobile.api.IMobileConnectListener;
import com.aliyun.alink.linksdk.channel.mobile.api.IMobileDownstreamListener;
import com.aliyun.alink.linksdk.channel.mobile.api.IMobileRequestListener;
import com.aliyun.alink.linksdk.channel.mobile.api.IMobileSubscrbieListener;
import com.aliyun.alink.linksdk.channel.mobile.api.MobileChannel;
import com.aliyun.alink.linksdk.channel.mobile.api.MobileConnectConfig;
import com.aliyun.alink.linksdk.channel.mobile.api.MobileConnectState;
import com.aliyun.alink.linksdk.tmp.data.SubDevInfo;
import com.aliyun.alink.linksdk.tmp.service.DevService;
import com.aliyun.alink.linksdk.tmp.utils.TmpEnum;
import com.aliyun.alink.linksdk.tools.ALog;
import com.aliyun.alink.linksdk.tools.ThreadTools;
import com.aliyun.iot.aep.sdk.IoTSmart;
import com.aliyun.iot.aep.sdk.apiclient.IoTAPIClient;
import com.aliyun.iot.aep.sdk.apiclient.IoTAPIClientFactory;
import com.aliyun.iot.aep.sdk.apiclient.IoTAPIClientImpl;
import com.aliyun.iot.aep.sdk.apiclient.callback.IoTCallback;
import com.aliyun.iot.aep.sdk.apiclient.callback.IoTResponse;
import com.aliyun.iot.aep.sdk.apiclient.request.IoTRequest;
import com.aliyun.iot.aep.sdk.apiclient.request.IoTRequestBuilder;
import com.aliyun.iot.aep.sdk.apiclient.adapter.APIGatewayHttpAdapterImpl;
import com.aliyun.iot.aep.sdk.apiclient.callback.IoTCallback;
import com.aliyun.iot.aep.sdk.apiclient.emuns.Env;
import com.aliyun.iot.aep.sdk.apiclient.emuns.Scheme;
import com.aliyun.iot.aep.sdk.apiclient.hook.IoTAuthProvider;
import com.aliyun.iot.aep.sdk.apiclient.request.IoTRequest;
import com.aliyun.iot.aep.sdk.apiclient.request.IoTRequestBuilder;
import com.aliyun.iot.aep.sdk.credential.IoTCredentialProviderImpl;
import com.aliyun.iot.aep.sdk.credential.IotCredentialManager.IoTCredentialListener;
import com.aliyun.iot.aep.sdk.credential.IotCredentialManager.IoTCredentialManage;
import com.aliyun.iot.aep.sdk.credential.IotCredentialManager.IoTCredentialManageError;
import com.aliyun.iot.aep.sdk.credential.IotCredentialManager.IoTCredentialManageImpl;
import com.aliyun.iot.aep.sdk.credential.data.IoTCredentialData;
import com.aliyun.iot.aep.sdk.framework.AApplication;
import com.aliyun.iot.aep.sdk.login.ILoginCallback;
import com.aliyun.iot.aep.sdk.login.ILogoutCallback;
import com.aliyun.iot.aep.sdk.login.LoginBusiness;
// import com.aliyun.iot.breeze.api.Config;
// import com.aliyun.iot.breeze.api.Factory;
import com.aliyun.iot.breeze.api.IAuthCallback;
// import com.aliyun.iot.breeze.api.IBreeze;
// import com.aliyun.iot.breeze.mix.MixBleDelegate;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableMap;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

// ref to https://gaic.alicdn.com/ztms/ilop-ApiReference-V5/allclasses-noframe.html

public class FYSDK {
    private static FYSDK mSDK;
    private Context mContext;
    public AApplication mApplication;
    private AliLiving mRnModule;
    private Promise mConfigNodePromise;
    private String iotIdAdding;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    public List<String> fullTopics = new ArrayList<>();
    private EventListener socketEvent;
    private IMobileConnectListener mIMobileConnectListener = new IMobileConnectListener() {
        @Override
        public void onConnectStateChange(MobileConnectState state) {
            ALog.d(AliLiving.TAG,"onConnectStateChange(), state = "+state.toString());
            if(state == MobileConnectState.CONNECTED){


            }
        }
    };

    public static final String TAG = FYSDK.class.getSimpleName();
    public static FYSDK getInstance(Context context, Application application, AliLiving rnModule){
        if (mSDK == null){
            mSDK =new FYSDK(context, application, rnModule);
        }
        return mSDK;
    }

    public FYSDK(Context context, Application application, AliLiving rnModule){
        this.mContext = context;
        // this.mApplication = application;
        this.mApplication = AApplication.getInstance();
        this.mRnModule = rnModule;
    }

    public void init(){
        // 其他 SDK, 仅在 主进程上初始化
        String packageName = this.mApplication.getPackageName();
        if (!packageName.equals(ThreadTools.getProcessName(this.mApplication, android.os.Process.myPid()))) {
            return;
        }

        // ConfigManager.getInstance().setBundleName("com.aliyun.iot.demo");
        SDKInitHelper.init(this.mApplication);

        // 如果你在 dependency.gradle 中使用
        // com.aliyun.alink.linksdk:lpbs-plugin-breeze:1.2.2
        // 而且碰到如下错误
        // 02-22 12:42:41.005: E/AndroidRuntime(13595): java.lang.NullPointerException: Attempt to invoke virtual method 'void com.aliyun.iot.breeze.mix.MixBleScanner.stopLeScan(com.aliyun.iot.breeze.mix.LeScanCallBack)' on a null object reference
        // 02-22 12:42:41.005: E/AndroidRuntime(13595):    at com.aliyun.iot.breeze.mix.MixBleDelegate.stopLeScan(MixBleDelegate.java:63)
        // 02-22 12:42:41.005: E/AndroidRuntime(13595):    at com.aliyun.iot.breeze.lpbs.Discovery.stopDiscovery(Discovery.java:59)
        // 02-22 12:42:41.005: E/AndroidRuntime(13595):    at com.aliyun.alink.linksdk.alcs.lpbs.a.e.f.stopDiscovery(MainDataConvertLayer.java:302)
        // 02-22 12:42:41.005: E/AndroidRuntime(13595):    at com.aliyun.alink.linksdk.alcs.lpbs.a.e.e.stopDiscovery(IAlcsPalLayer.java:192)
        // 导致 APP 崩溃的话，除了退回使用
        // com.aliyun.alink.linksdk:lpbs-plugin-breeze:1.2.1
        // 外，也可以使用下面几行代码避免之
        // IBreeze breeze = Factory.createBreeze(this.mContext);
        // breeze.configure(new Config.Builder().debug(true).log(true).logLevel(1).build());
        // MixBleDelegate.getInstance().init(this.mContext, breeze);

        // 上面是 API Level 9 SDK 及以上的统一初始化，
        // 下面是 API Level 8 SDK 之前的每个SDK分别初始化，
        // 等本组件稳定后可考虑删除下面的代码
//         //飞燕初始化
// //        try {
// //            SecurityInit.Initialize(this.mContext);
// //        } catch (JAQException ex) {
// //            Log.e(AliLiving.TAG, "security-sdk-initialize-failed");
// //        } catch (Exception ex) {
// //            Log.e(AliLiving.TAG, "security-sdk-initialize-failed");
// //        }

//         Log.d(AliLiving.TAG,"FYSDK init");
//         // 初始化无线保镖
//         try {
//             SecurityInit.Initialize(this.mContext);
//         } catch (JAQException ex) {
//             String errorMsg = ex.getMessage();
//             int errorCode = ex.getErrorCode();
//             Log.e(AliLiving.TAG, "security-sdk-initialize-failed");
//         } catch (Exception ex) {
//             Log.e(AliLiving.TAG, "security-sdk-initialize-failed");
//         }
// //        InitResultCallback callback =  new InitResultCallback() {
// //            @Override
// //            public void onFailure(int i, String s) {
// //                //从这里可以打印出失败原因
// //                Log.i(AliLiving.TAG,"init fail   ------"+s);
// //            }
// //
// //            @Override
// //            public void onSuccess() {
// //                ALog.setLevel(ALog.LEVEL_DEBUG);
// //
// //                Log.i(AliLiving.TAG,"init success");
// //                // 初始化 IoTAPIClient
// //                IoTAPIClientImpl.InitializeConfig config = new IoTAPIClientImpl.InitializeConfig();
// //                config.host = "api.link.aliyun.com";
// //                config.apiEnv = Env.RELEASE;
// //                IoTAPIClientImpl impl = IoTAPIClientImpl.getInstance();
// //                impl.init(mContext, config);
// ////                impl.registerTracker(new MainActivity.Tracker());
// //
// //                String appKey = APIGatewayHttpAdapterImpl.getAppKey(mContext, "114d");
// //                try{
// //                    //api认证通道
// //                    IoTCredentialManageImpl.init(appKey);
// //                    IoTAuthProvider provider = new IoTCredentialProviderImpl(IoTCredentialManageImpl.getInstance(FYSDK.this.mApplication));
// //                    impl.registerIoTAuthProvider("iotAuth", provider);
// //                }catch (Exception e){
// //                    Log.e(AliLiving.TAG,e.getMessage(),e);
// //                }
// //
// //                //长连接初始化
// //                MobileConnectConfig mobileConfig = new MobileConnectConfig();
// //                // 设置 appKey 和 authCode(必填)
// //                mobileConfig.appkey =appKey;
// //                mobileConfig.securityGuardAuthcode = "114d";
// //                MobileChannel.getInstance().startConnect(mContext, mobileConfig, mIMobileConnectListener);
// //            }
// //        };
// //
// //        LoginBusiness.init(this.mContext,new OALoginAdapter(this.mContext,callback),"ONLINE");
//         LoginBusiness.init(this.mContext, new OALoginAdapter(this.mContext, new InitResultCallback() {
//             @Override
//             public void onSuccess() {
//                 ALog.setLevel(ALog.LEVEL_DEBUG);

//                 Log.i(AliLiving.TAG,"init success");
//                 // 初始化 IoTAPIClient
//                 IoTAPIClientImpl.InitializeConfig config = new IoTAPIClientImpl.InitializeConfig();
//                 config.host = "api.link.aliyun.com";
//                 config.apiEnv = Env.RELEASE;
//                 IoTAPIClientImpl impl = IoTAPIClientImpl.getInstance();
//                 impl.init(mContext, config);
// //                impl.registerTracker(new MainActivity.Tracker());

//                 String appKey = APIGatewayHttpAdapterImpl.getAppKey(mContext, "114d");
//                 try{
//                     //api认证通道
//                     IoTCredentialManageImpl.init(appKey);
//                     IoTAuthProvider provider = new IoTCredentialProviderImpl(IoTCredentialManageImpl.getInstance(FYSDK.this.mApplication));
//                     impl.registerIoTAuthProvider("iotAuth", provider);
//                 }catch (Exception e){
//                     Log.e(AliLiving.TAG,e.getMessage(),e);
//                 }

//                 //长连接初始化
//                 MobileConnectConfig mobileConfig = new MobileConnectConfig();
//                 // 设置 appKey 和 authCode(必填)
//                 mobileConfig.appkey =appKey;
//                 mobileConfig.securityGuardAuthcode = "114d";
//                 MobileChannel.getInstance().startConnect(mContext, mobileConfig, mIMobileConnectListener);

//             }

//             @Override
//             public void onFailure(int i, String s) {

//                 Log.d(AliLiving.TAG,s);
//             }
//         }),false,"ONLINE");
    }
    //登录
    public void login(ILoginCallback callback){
        LoginBusiness.login(callback);
    }
    //退出登录
    public void logout(ILogoutCallback callback){
        LoginBusiness.logout(callback);
    }
    //登录状态
    public boolean isLogin(){
        return LoginBusiness.isLogin();
    }
    //搜寻设备
    public void startScanLocalDevice(final EventListener event, EnumSet<DiscoveryType> enumSet, Boolean unclaimed){
        IDeviceDiscoveryListener listener = new IDeviceDiscoveryListener() {
            @Override
            public void onDeviceFound(DiscoveryType discoveryType, List<DeviceInfo> foundDeviceList) {
                Log.i(AliLiving.TAG,"find " + foundDeviceList.size() + " " + discoveryType.getDescription());
                for (int i = 0;i<foundDeviceList.size();i++){
                    DeviceInfo deviceInfo = foundDeviceList.get(i);

// // When unclaimed == true with device of `dev_ap start`
// find 1 soft ap provision device
// {
//     "id": "00A1DB",
//     "linkType": "ForceAliLinkTypeNone",
//     "productKey": "a17hN4W4777",
//     "deviceName": "null",
//     "productId": "null",
//     "devType": "null",
//     "remainTime": "null",
//     "mac": "null",
//     "addDeviceFrom": "null",
//     "regProductKey": "null",
//     "regDeviceName": "null",
//     "protocolVersion": "1.0",
//     "service": "null",
//     "fwVersion": "null",
//     "token": "null",
//     "tag": "1606351779712",
//     "regionInfo": "null",
//     "extraDeviceInfo": "{apSsid=adh_a17hN4W4777_00A1DB, apBssid=a0:fb:42:00:a1:da}",
//     "bindResultInfo": "null",
//     "iotId": "null",
//     "regIotId": "null",
//     "deviceId": "null"
// }

// // When unclaimed == true with device of `ble_awss start`
// find 1 combo device broadcast with subType = 0x03
// {
//     "id": "00A1DB",
//     "linkType": "ForceAliLinkTypeNone",
//     "productKey": "null",
//     "deviceName": "null",
//     "productId": "6266777",
//     "devType": "ble_subtype_3",
//     "remainTime": "null",
//     "mac": "A0:FB:42:00:A1:DB",
//     "addDeviceFrom": "null",
//     "regProductKey": "null",
//     "regDeviceName": "null",
//     "protocolVersion": "1.0",
//     "service": "null",
//     "fwVersion": "null",
//     "token": "null",
//     "tag": "1606272016337",
//     "regionInfo": "null",
//     "extraDeviceInfo": "{resetFlag=true}",
//     "bindResultInfo": "null",
//     "iotId": "null",
//     "regIotId": "null",
//     "deviceId": "null"
// }

// // When unclaimed == false
// find 1 wifi or ethernet online device
// {
//     "id": "00A1DB",
//     "linkType": "ForceAliLinkTypeNone",
//     "productKey": "a17hN4W4777",
//     "deviceName": "testDeviceName1",
//     "productId": "null",
//     "devType": "0",
//     "remainTime": "null",
//     "mac": "A0:FB:42:00:A1:DB",
//     "addDeviceFrom": "null",
//     "regProductKey": "null",
//     "regDeviceName": "null",
//     "protocolVersion": "1.0",
//     "service": "null",
//     "fwVersion": "null",
//     "token": "C0DFBDC39B8D0C26F7392C31D7859266",
//     "tag": "1606272695871",
//     "regionInfo": "null",
//     "extraDeviceInfo": "null",
//     "bindResultInfo": "null",
//     "iotId": "null",
//     "regIotId": "null",
//     "deviceId": "null"
// }

                    ALog.d(AliLiving.TAG, deviceInfo.toString());

                    if (unclaimed) { // iOS startDiscoveryWithFilter:@{@"deviceType":@[@"breeze"]} will get online and combo device, so use unclaimed here as iOS dose
                        if (deviceInfo.productKey == null) {
                            provisionDevicePidtoPk(event, discoveryType, deviceInfo);
                        }
                    } else {
                        if (deviceInfo.productKey != null) {
                            JSONObject device = new JSONObject();
                            try {
                                device.put("macAddress", deviceInfo.mac);
                                device.put("meshUUID", discoveryType.getType());
                                device.put("productUUID", deviceInfo.productKey);
                                if (!TextUtils.isEmpty(deviceInfo.token)) {
                                    device.put("token", deviceInfo.token);
                                }
                                event.onEvent(AliLiving.LE_SCAN, device);
                            } catch (JSONException e) {
                                Log.e(AliLiving.TAG, e.getMessage());
                            }
                        }
                    }
                }
            }
        };
        LocalDeviceMgr.getInstance().startDiscovery(this.mContext,enumSet,null,listener);
    }
    //停止搜索设备
    public void stopScanLocalDevice(){
        LocalDeviceMgr.getInstance().stopDiscovery();
    }

    // productId 换 productKey
    private void provisionDevicePidtoPk(final EventListener event, DiscoveryType discoveryType, final DeviceInfo deviceInfo) {
        ALog.d(AliLiving.TAG, "provisionDevicePidtoPk");
        IoTRequest request = new IoTRequestBuilder()
                .setPath(APIConfig.PROVISION_DEVICE_PIDTOPK)
                .setApiVersion(APIConfig.PROVISION_DEVICE_PIDTOPK_VERSION)
                .addParam(IAuthCallback.PARAM_PRODUCT_ID, deviceInfo.productId)
                .setAuthType("iotAuth")
                .build();

        IoTAPIClient ioTAPIClient = new IoTAPIClientFactory().getClient();
        ioTAPIClient.send(request, new IoTCallback() {
            @Override
            public void onFailure(IoTRequest ioTRequest, final Exception e) {
                ALog.e(AliLiving.TAG, "provisionDevicePidtoPk onFailure");
            }

            @Override
            public void onResponse(final IoTRequest ioTRequest, final IoTResponse ioTResponse) {
                if (200 != ioTResponse.getCode() || !(ioTResponse.getData() instanceof JSONObject)) {
                    ALog.e(AliLiving.TAG, "provisionDevicePidtoPk" + ioTResponse.getCode() + ioTResponse.getMessage() + ioTResponse.getLocalizedMsg());
                    return;
                }

                JSONObject data = (JSONObject) ioTResponse.getData();
                String productKey = data.optString("productKey");
                ALog.d(AliLiving.TAG, "provisionDevicePidtoPk productKey: " + productKey);

                JSONObject device = new JSONObject();
                try {
                    device.put("macAddress", deviceInfo.mac);
                    device.put("meshUUID", discoveryType.getType());
                    device.put("productUUID", productKey);
                    if (!TextUtils.isEmpty(deviceInfo.token)) {
                        device.put("token", deviceInfo.token);
                    }
                    event.onEvent(AliLiving.LE_SCAN, device);
                } catch (JSONException e) {
                    Log.e(AliLiving.TAG, e.getMessage());
                }
            }
        });
    }

    public void provisionDeviceInfo(String productKey, Promise promise){
        ALog.d(AliLiving.TAG, "provisionDeviceInfo by productKey: " + productKey);
        IoTRequest request = new IoTRequestBuilder()
                .setPath(APIConfig.ME_OTA_PRODUCT_KEY_INFO) // PROVISION_DEVICE_INFO will cause '20050 productkey required'
                .setApiVersion(APIConfig.ME_OTA_PRODUCT_KEY_INFO_VERSION)
                .addParam(IAuthCallback.PARAM_PRODUCT_KEY, productKey)
                .setAuthType("iotAuth")
                .build();

        IoTAPIClient ioTAPIClient = new IoTAPIClientFactory().getClient();
        ioTAPIClient.send(request, new IoTCallback() {
            @Override
            public void onFailure(IoTRequest ioTRequest, final Exception e) {
                ALog.e(AliLiving.TAG, "provisionDeviceInfo onFailure");
            }

            @Override
            public void onResponse(final IoTRequest ioTRequest, final IoTResponse ioTResponse) {
                if (200 != ioTResponse.getCode() || !(ioTResponse.getData() instanceof JSONObject)) {
                    ALog.e(AliLiving.TAG, "provisionDeviceInfo " + ioTResponse.getCode() + " " + ioTResponse.getMessage());
                    promise.reject("provisionDeviceInfo " + ioTResponse.getCode() + " " + ioTResponse.getMessage());
                    return;
                }

                try {
                    promise.resolve(JsonConvert.jsonToReact((JSONObject) ioTResponse.getData()));
                } catch (JSONException e) {
                    promise.reject("provisionDeviceInfo json error");
                }
            }
        });
    }

    // 蓝牙设备上线
    // breezeSubLogin 入参是 pk 和mac 通过这两个值来上线蓝牙设备，上线完后回调里面会返回 deviceName 。
    // 上线后，可在生活物联网平台设备详情页面中看到状态变成了在线，
    // 以及 IP 地址（实际上是自动将手机创建为一个网关，这个手机的 IP 地址），
    // 如果此时退出 APP ，则设备详情页面中就会看到状态变成了离线。
    // 此处上线只是用于蓝牙设备的激活，并不能用于设备跟云端交换数据。
    // 在 userBindByTimeWindow 绑定结束后，蓝牙设备就会下线掉。
    // 绑定后随时可以解绑。解绑跟其他配网方式的设备一样，因为
    // 执行恢复出厂设置任务 https://help.aliyun.com/document_detail/177871.html
    // 只是在云端解绑用户跟设备的绑定关系，不会对设备做恢复出厂设置的事情。
    // 设备恢复出厂设置，需要引导用户去按物理键进行。
    public void breezeSubDevLogin(final String productKey, final String macAddress, String ssid, String password, Promise promise) {
        WritableMap params = Arguments.createMap();
        params.putString("status", "LoginingBluetoothDevice");
        mRnModule.sendEvent(AliLiving.DEVICE_STATUS_UPDATING_MESH, params);

        DevService.breezeSubDevLogin(productKey, macAddress, new DevService.ServiceListener() {
            @Override
            public void onComplete(boolean b, Object o) {
                ALog.d(AliLiving.TAG, "breezeSubDevLogin onComplete isSuccess:" + b + " bundle:" + o);
                ThreadTools.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (b && o instanceof Map) {
                            Map<String, Object> bundle = (Map<String, Object>) o;
                            String pk = bundle.get(DevService.BUNDLE_KEY_PRODUCTKEY).toString();
                            String dn = bundle.get(DevService.BUNDLE_KEY_DEVICENAME).toString();
                            ALog.d(AliLiving.TAG, "bluetooth device login pk->" + pk + " dn->" + dn);
                            ALog.d(AliLiving.TAG, "comboDeviceStartBindBle");

                            userBindByTimeWindow(pk, dn, macAddress, ssid, password, ILopNetTypeCodes.NET_TYPE_BT, promise);
                        } else {
                            promise.reject(new Exception("breezeSubDevLogin failure"));
                        }
                    }
                });
            }
        });
    }

    // 基于时间窗口方式绑定设备
    private void userBindByTimeWindow(final String productKey, final String deviceName, final String macAddress, String ssid, String password, String netType, Promise promise) {
        ALog.d(AliLiving.TAG, "userBindByTimeWindow " + this);
        Map<String, Object> map = new HashMap<>();
        map.put("productKey", productKey);
        map.put("deviceName", deviceName);
        IoTRequest request = new IoTRequestBuilder()
                .setPath(APIConfig.PROVISION_DEVICE_TIME_BIND)
                .setApiVersion(APIConfig.PROVISION_DEVICE_TIME_BIND_VERSION)
                .setParams(map)
                .setAuthType("iotAuth")
                .build();
        new IoTAPIClientFactory().getClient().send(request, new IoTCallback() {
            @Override
            public void onFailure(IoTRequest ioTRequest, Exception e) {
                ALog.e(AliLiving.TAG, "userBindByTimeWindow error", e);
                promise.reject(e);
            }

            @Override
            public void onResponse(IoTRequest ioTRequest, IoTResponse ioTResponse) {
                if (ioTResponse.getCode() == 200) {
                    JSONObject data = (JSONObject) ioTResponse.getData();
                    String iotId = data.optString("iotId");

                    iotIdAdding = iotId;
                    mRnModule.insertDevice(iotId);

                    // TMP 是设备控制相关的sdk，设备绑定成功都会通知 tmp 设备已经绑定了，
                    // 针对蓝牙 Combo 设备来说的意义就是，将密钥写到设备里面去。
                    // 必须要有的，不然会有控制上的问题。
                    tmpNotify(iotId, deviceName, macAddress, netType, productKey, ssid, password, promise);
                } else {
                    String message = "userBindByTimeWindow " + ioTResponse.getCode() + " " + ioTResponse.getMessage();
                    ALog.e(AliLiving.TAG, message);
                    promise.reject(message);
                }
            }
        });
    }

    private void tmpNotify(String iotId, final String deviceName, final String macAddress, String netType, final String productKey, String ssid, String password, Promise promise) {
        ALog.d(AliLiving.TAG, "tmpNotify iotId->" + iotId);
        SubDevInfo subDevInfo = new SubDevInfo();
        subDevInfo.iotId = iotId;
        if (netType == ILopNetTypeCodes.NET_TYPE_BT) {
            ALog.d(AliLiving.TAG, "tmpNotify macAddress->" + macAddress);
            subDevInfo.deviceName = macAddress;
        } else {
            ALog.d(AliLiving.TAG, "tmpNotify deviceName->" + deviceName);
            subDevInfo.deviceName = deviceName;
        }
        subDevInfo.productKey = productKey;

        WritableMap params = Arguments.createMap();
        params.putString("status", "WritingBluetoothToken");
        mRnModule.sendEvent(AliLiving.DEVICE_STATUS_UPDATING_MESH, params);

        DevService.notifySubDeviceBinded(subDevInfo, new DevService.ServiceListener() {
            @Override
            public void onComplete(boolean isSuccess, @Nullable Object o) {
                ALog.d(AliLiving.TAG, "notifySubDeviceBinded isSuccess->" + isSuccess);
                if (isSuccess) {
                    // if wifiConnect don't wait this isSuccess,
                    // sometimes will cause
                    //     <E> err at 0x0013, code 0x0008
                    //     <E> err at 0x0016, code 0x0009
                    // in firmware printf
                    wifiConnect(macAddress, iotId, ssid, password, promise);
                } else {
                    if (iotIdAdding != null) {
                        mRnModule.removeDevice(iotIdAdding);
                        iotIdAdding = null;
                    }
                    promise.reject(new Exception("DevService.notifySubDeviceBinded failure"));
                }
            }
        });
    }

    public void getCurrentSsid(Promise promise){
        String ssid = AddDeviceBiz.getInstance().getCurrentSsid(this.mApplication);
        ALog.d(AliLiving.TAG, "getCurrentSsid " + ssid);
        promise.resolve(ssid);
    }

    public void notifyWiFiStatus(String iotId, TmpEnum.DeviceWifiStatus wifiStatus) {
        ALog.d(AliLiving.TAG, "notifyWiFiStatus iotId->" + iotId + "wifiStatus" + wifiStatus.getValue());
        DevService.setWifiStatus(iotId, wifiStatus, new DevService.ServiceListenerEx() {
            @Override
            public void onComplete(boolean b, @Nullable String s) {
                ALog.d(AliLiving.TAG, "notifyWiFiStatus->" + b + "iotId" + iotId);
            }
        });
    }

    // 添加配网设备
    public void wifiConnect(String mac, String iotId, String ssid, String password, Promise promise) {
// 10-30 16:08:35.022: D/AliLiving(4275): connect result: status:true bundle:{bundlekey_subchannel=com.aliyun.alink.linksdk.channel.gateway.a.c@37771fc,
//                                        bundlekey_productkey=a17hN4W4777, bundlekey_devicename=testDeviceName1}
// 10-30 16:08:35.022: D/AliLiving(4275): breezeSubDevLogin success
// 10-30 16:08:35.022: D/AliLiving(4275): bluetooth device login pk->a17hN4W4777 dn->testDeviceName1
// 10-30 16:08:35.022: D/AliLiving(4275): comboDeviceStartBindBle
// 10-30 16:08:35.022: D/AliLiving(4275): userBindByTimeWindow ugen.fy.plugin.FYSDK@2f551d7
// 10-30 16:08:35.488: D/AliLiving(4275): tmpNotify iotId->vvssa4DEzVglIGxDls25000000
// 10-30 16:08:35.489: D/AliLiving(4275): tmpNotify macAddress->C8:47:8C:00:07:77
// 10-30 16:08:35.543: D/AliLiving(4275): wifiConnect comboDeviceStartDistributionNetwork mac->C8:47:8C:00:07:77
// 10-30 16:08:35.543: D/AliLiving(4275): wifiConnect startAddDevice
// 10-30 16:08:35.553: D/AliLiving(4275): toggleProvision s:YOUR_SSID p:YOUR_PASSWORD timeout:60s
// 10-30 16:08:35.582: I/AliLiving(4275): startAddDevice onProvisioning
// 10-30 16:08:35.582: D/AliLiving(4275): startAddDevice onProvisionStatus ProvisionStatus[code=305,message=scan target ble device success from user.,
//                                        extraParams={devType=ble_subtype_3, ble_mac=C8:47:8C:00:07:77, productId=null}]
// 10-30 16:08:35.582: D/AliLiving(4275): startAddDevice BLE_DEVICE_SCAN_SUCCESS
// 10-30 16:08:35.582: D/AliLiving(4275): devType->ble_subtype_3 bleMac->C8:47:8C:00:07:77 prouctID->null
// 10-30 16:08:36.417: D/AliLiving(4275): startAddDevice onProvisionStatus ProvisionStatus[code=100,message=notify app bind token,
//                                        extraParams={appToken=3A17D165B8ECA10070BCE42D61268777}]
// 10-30 16:08:45.406: D/AliLiving(4275): onProvisionedResult isSuccess:true deviceInfo:{"id":"null","linkType":"ForceAliLinkTypeNone",
//                                        "productKey":"a17hN4W4777","deviceName":"testDeviceName1","productId":"null","devType":"null",
//                                        "remainTime":"null","mac":"null","addDeviceFrom":"null","regProductKey":"null",
//                                        "regDeviceName":"null","protocolVersion":"1.0","service":"null","fwVersion":"null",
//                                        "token":"null","tag":"null","regionInfo":"null","extraDeviceInfo":"null","bindResultInfo":"null",
//                                        "iotId":"null","regIotId":"null","deviceId":"null"} dcErrorCode:null
// 10-30 16:08:45.411: D/AliLiving(4275): stopToogle stopAddDevice
// 10-30 16:08:45.411: D/AliLiving(4275): toogle comboDeviceStartDistributionNetwork success

        ALog.d(AliLiving.TAG, "wifiConnect comboDeviceStartDistributionNetwork mac->" + mac);
        ALog.d(AliLiving.TAG, "wifiConnect startAddDevice");
        // notifyWiFiStatus(iotId, TmpEnum.DeviceWifiStatus.DeviceWifiStatus_Setting);
        DeviceInfo deviceInfo = buildDeviceInfo(mac);
        AddDeviceBiz.getInstance().setDevice(deviceInfo);

        // 配网过程需要位置权限和位置服务，在调用开始配网接口之前，请确保 APP 已获得相关权限。
        // 如使用手机热点方式配网， APP 还需额外获得 WRITE_SETTINGS 的权限。
        AddDeviceBiz.getInstance().startAddDevice(this.mApplication, new IAddDeviceListener() {
            @Override
            public void onPreCheck(boolean b, DCErrorCode dcErrorCode) {
                // 参数检测回调
                Log.d(AliLiving.TAG, "startAddDevice onPreCheck " + dcErrorCode.code + " " + dcErrorCode.codeName);
            }

            @Override
            public void onProvisionPrepare(int prepareType) {
                Log.d(AliLiving.TAG, "startAddDevice onProvisionPrepare prepareType->" + prepareType);
                if (prepareType == 1) {
                    // 一键配网、蓝牙辅助配网、设备热点配网、二维码配网、手机热点配网会走到该流程
                    // 之后调用 toggleProvision 接口开始配网

                    WritableMap params = Arguments.createMap();
                    params.putString("status", "ConfigingWiFi");
                    mRnModule.sendEvent(AliLiving.DEVICE_STATUS_UPDATING_MESH, params);

                    mConfigNodePromise = promise;
                    toggleProvision(ssid, password);
                } else if (prepareType == 2) {
                   // 手机热点配网时可能会走到该流程以便提示用户开启手机热点
                }
            }

            @Override
            public void onProvisioning() {
                // 配网中
                Log.d(AliLiving.TAG, "startAddDevice onProvisioning");
            }

            @Override
            public void onProvisionStatus(ProvisionStatus provisionStatus) {
                // 二维码配网
                // provisionStatus=ProvisionStatus.QR_PROVISION_READY表示二维码ready了
                // ProvisionStatus.QR_PROVISION_READY.message() 获取二维码内容
                // 注意：返回二维码时已开启监听设备是否已配网成功的通告，并开始计时，UI端应提示用户尽快扫码，
                // 如果在指定时间配网超时了，重新调用开始配网流程并刷新二维码。

                // 设备热点配网
                // 只有需要提示用户需要手动连接设备热点或者恢复Wi-Fi连接的场景才会回调，
                // 比如android 10，或者非android 10发现或连接设备热点失败。
                // provisionStatus=ProvisionStatus.SAP_NEED_USER_TO_CONNECT_DEVICE_AP 表示需要用户手动连接设备热点，
                // provisionStatus=ProvisionStatus.SAP_NEED_USER_TO_RECOVER_WIFI 表示需要用户手动恢复到配网之前的Wi-Fi，
                // 针对android 10不支持的场景，可以根据这两个事件增加交互，让用户处理。

                ALog.d(AliLiving.TAG, "startAddDevice onProvisionStatus " + provisionStatus.toString());
                if ((provisionStatus != null) && provisionStatus.code() == ProvisionStatus.BLE_DEVICE_SCAN_SUCCESS.code()) {
                    ALog.d(AliLiving.TAG, "startAddDevice BLE_DEVICE_SCAN_SUCCESS");
                    if (provisionStatus.getExtraParams() != null) {
                        String devType = (String) provisionStatus.getExtraParams().get(ILopNetTypeCodes.KEY_DEV_TYPE);
                        String bleMac = (String) provisionStatus.getExtraParams().get(ILopNetTypeCodes.KEY_BLE_MAC);
                        String prouctID = (String) provisionStatus.getExtraParams().get(ILopNetTypeCodes.KEY_PRODUCT_ID);
                        ALog.d(AliLiving.TAG, "devType->" + devType + " bleMac->" + bleMac + " prouctID->" + prouctID);
                        if (ILopNetTypeCodes.DEV_TYPYE_BLE_SUBTYPE_3.equals(devType)) {
                            // 让底层 SDK 继续配网，目前业务暂时不用传入任何参数
                            AddDeviceBiz.getInstance().continueProvision(null);
                        }
                    }
                }
            }

            @Override
            public void onProvisionedResult(boolean isSuccess, DeviceInfo deviceInfo, DCErrorCode dcErrorCode) {
                // some device sometimes can't enter here, that's why hackOnProvisionedResult() exist
                if (iotIdAdding != null) {
                    mRnModule.removeDevice(iotIdAdding);
                    iotIdAdding = null;
                }
                normalOnProvisionedResult(iotId, isSuccess, deviceInfo, dcErrorCode);
            }
        });
    }

    private DeviceInfo buildDeviceInfo(String mac) {
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.devType = ILopNetTypeCodes.DEV_TYPYE_BLE_SUBTYPE_3;
        deviceInfo.mac = mac;

        // 设备热点配网：ForceAliLinkTypeSoftAP
        // 蓝牙辅助配网：ForceAliLinkTypeBLE
        // 二维码配网：ForceAliLinkTypeQR
        // 手机热点配网：ForceAliLinkTypePhoneAP
        // 一键配网：ForceAliLinkTypeBroadcast
        // 零配：ForceAliLinkTypeZeroAP
        deviceInfo.linkType = LinkType.ALI_BLE.getName();

        // deviceInfo.id= "xxx";// 设备热点的 ID ，在发现热点设备返回到 APP 时会携带这个字段

        RegionInfo regionInfo = new RegionInfo();

        // 如果当前 APP 需要全球使用，且涉及到切换账号的数据中心，配网 SDK 可以按照以下设置传递数据中心的信息
        // 平台返回服务器 ID 的值如下
        // 0：上海
        // 1：新加坡
        // 3：美国
        // 4：德国
        // 阿里的人说，IoTSmart.getShortRegionId() 这个是由账号的注册地来决定的。
        // 也就是说，注册的时候选择国家是有意义的，但是登录的时候选择国家就没有意义了。
        regionInfo.shortRegionId = Integer.parseInt(IoTSmart.getShortRegionId());
        ALog.d(AliLiving.TAG, "shortRegionId: " + regionInfo.shortRegionId);

        deviceInfo.regionInfo = regionInfo;
        return deviceInfo;
    }

    private int toggleProvisionTimeoutSecond = 39; // 正常应该在 10 秒内配网成功

    private void toggleProvision(String ssid, String password) {
        stopToogleTimer();
        ALog.d(AliLiving.TAG, "toggleProvision s->" + ssid + " p->" + password + " timeout:" + toggleProvisionTimeoutSecond);
        AddDeviceBiz.getInstance().toggleProvision(ssid, password, 60);
        startToogleTimer();
    }

    private Timer toggTimer;

    private void stopToogleTimer() {
        if (toggTimer != null) {
            toggTimer.cancel();
            toggTimer = null;
        }
    }

    private void startToogleTimer() {
        toggTimer = new Timer();
        toggTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                ThreadTools.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        timeOut();
                    }
                });

            }
        }, toggleProvisionTimeoutSecond * 1000);
    }

    private void timeOut() {
        ALog.d(AliLiving.TAG, "toogle time out");
        if (mConfigNodePromise != null) {
            if (iotIdAdding != null) {
                mRnModule.removeDevice(iotIdAdding);
                iotIdAdding = null;
            }
            mConfigNodePromise.reject(new Exception("toogle time out"));
            mConfigNodePromise = null;
        }
        stopToogle();
    }

    private void stopToogle() {
        stopToogleTimer();
        ALog.d(AliLiving.TAG, "stopToogle stopAddDevice");
        AddDeviceBiz.getInstance().stopAddDevice();
    }

    public void hackOnProvisionedResult(String iotId) {
        if (iotId.equals(iotIdAdding)) {
            iotIdAdding = null;
            mRnModule.removeDevice(iotId);
            ALog.d(AliLiving.TAG, "startAddDevice hackOnProvisionedResult to help unstable onProvisionedResult");

            IoTRequest request = new IoTRequestBuilder()
                    .setPath(APIConfig.ME_OTA_GET_FIRMWARE_FILE)
                    .setApiVersion(APIConfig.ME_OTA_GET_FIRMWARE_FILE_VERSION)
                    .addParam("iotId", iotId)
                    .setAuthType("iotAuth")
                    .build();

            IoTAPIClient ioTAPIClient = new IoTAPIClientFactory().getClient();
            ioTAPIClient.send(request, new IoTCallback() {
                @Override
                public void onFailure(IoTRequest ioTRequest, final Exception e) {
                    ALog.e(AliLiving.TAG, "startAddDevice ME_OTA_GET_Firmware_VERSION onFailure");

                    DeviceInfo deviceInfo = new DeviceInfo();
                    deviceInfo.fwVersion = "V1.0.0-20211112.0503";
                    normalOnProvisionedResult(iotId, true, deviceInfo, null);
                }

                @Override
                public void onResponse(final IoTRequest ioTRequest, final IoTResponse ioTResponse) {
                    if (200 != ioTResponse.getCode() || !(ioTResponse.getData() instanceof JSONObject)) {
                        ALog.e(AliLiving.TAG, "startAddDevice ME_OTA_GET_Firmware_VERSION " + ioTResponse.getCode() + ioTResponse.getMessage() + ioTResponse.getLocalizedMsg());

                        DeviceInfo deviceInfo = new DeviceInfo();
                        deviceInfo.fwVersion = "V1.0.0-20211112.0503";
                        normalOnProvisionedResult(iotId, true, deviceInfo, null);
                        return;
                    }

                    JSONObject data = (JSONObject) ioTResponse.getData();
                    DeviceInfo deviceInfo = new DeviceInfo();
                    deviceInfo.fwVersion = data.optString("currentVersion");
                    normalOnProvisionedResult(iotId, true, deviceInfo, null);
                }
            });
        }
    }

    private void normalOnProvisionedResult(String iotId, boolean isSuccess, DeviceInfo deviceInfo, DCErrorCode dcErrorCode) {
        // 处理配网结果，如果配网成功后包含 token ，请使用配网成功带的 token 做绑定。

        iotIdAdding = null;

        String message = "startAddDevice onProvisionedResult isSuccess:" + isSuccess + " deviceInfo:" + deviceInfo.toString() + " dcErrorCode:" + dcErrorCode;
        ALog.d(AliLiving.TAG, message);
        ThreadTools.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                stopToogle();
                if (isSuccess) {
                    ALog.d(AliLiving.TAG, "toogle comboDeviceStartDistributionNetwork success");

                    JSONObject jsonObject = new JSONObject();
                    JSONObject nodeInfo = new JSONObject();
                    try {
                        jsonObject.put("meshAddress", iotId);
                        nodeInfo.put("v", deviceInfo.fwVersion);
                        jsonObject.put("nodeInfo", nodeInfo);
                        if (mConfigNodePromise != null) {
                            mConfigNodePromise.resolve(JsonConvert.jsonToReact(jsonObject));
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    mRnModule.insertDevice(iotId);
                    // notifyWiFiStatus(iotId, TmpEnum.DeviceWifiStatus.DeviceWifiStatus_Set);
                } else {
                    ALog.d(AliLiving.TAG, "toogle comboDeviceStartDistributionNetwork failure");
                    if (mConfigNodePromise != null) {
                        mConfigNodePromise.reject(new Exception("startAddDevice onProvisionedResult dcErrorCode:" + dcErrorCode));
                    }
                    // notifyWiFiStatus(iotId, TmpEnum.DeviceWifiStatus.DeviceWifiStatus_NotSet);
                }

                mConfigNodePromise = null;
            }
        });
    }

    //停止添加设备
    public void stopAddDevice(){
        ALog.d(AliLiving.TAG, "stopAddDevice stopAddDevice");
        AddDeviceBiz.getInstance().stopAddDevice();
    }
    //添加配网的wifi信息
    public void toggleProvision(String ssid,String password,int timeout){
        AddDeviceBiz.getInstance().toggleProvision(ssid, password, timeout);
    }

    // 获取设备token
    public void getDeviceToken(String productKey, String deviceName, String timeout, final Promise promise) {
        Integer time = Integer.valueOf(timeout);
        IOnDeviceTokenGetListener listener = new IOnDeviceTokenGetListener() {
            @Override
            public void onSuccess(String s) {
                promise.resolve(s);
            }
            @Override
            public void onFail(String s) {
                promise.reject("567", s);
            }
        };
        LocalDeviceMgr.getInstance().getDeviceToken(mContext, productKey, deviceName, time * 1000, listener);
    }

    public void getRefreshIotToken(IoTCredentialListener listener) {
        IoTCredentialManage ioTCredentialManage = IoTCredentialManageImpl.getInstance(mApplication);
        ioTCredentialManage.asyncRefreshIoTCredential(listener);
    }

    // 开启长连接
    public void startAliSocketListener(final Promise promise) {
        IMobileRequestListener mobileRequestListener = new IMobileRequestListener() {
            @Override
            public void onSuccess(String s) {
                promise.resolve(s);
            }

            @Override
            public void onFailure(AError aError) {
                promise.reject(new Exception("bindAccount failure"));
            }
        };

        // token 刷新 callback
        IoTCredentialListener listener = new IoTCredentialListener() {
            @Override
            public void onRefreshIoTCredentialSuccess(IoTCredentialData ioTCredentialData) {
                MobileChannel.getInstance().bindAccount(ioTCredentialData.iotToken, mobileRequestListener);
            }

            @Override
            public void onRefreshIoTCredentialFailed(IoTCredentialManageError ioTCredentialManageError) {
                promise.reject(new Exception("asyncRefreshIoTCredential failure"));
            }
        };

        // 开启长连接前需要刷新 token
        this.getRefreshIotToken(listener);
    }


    final IMobileDownstreamListener mobileDownstreamListener = new IMobileDownstreamListener() {
        @Override
        public void onCommand(String topic, String data) {
            Log.d(AliLiving.TAG, "downstream onCommand topic=" + topic + ", data=" + data);
            JSONObject json = new JSONObject();
            try {
                json.put("data", data);
                json.put("topic", topic);
                socketEvent.onEvent("subscribeDownstream", json);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        @Override
        public boolean shouldHandle(String topic) {
            // Log.d(AliLiving.TAG, "downstream shouldHandle topic=" + topic);
            for (String fullTopic : fullTopics) {
                // Log.d(AliLiving.TAG, "downstream fullTopic=" + fullTopic);
// with subscribe('/thing/properties') then change some properties
// downstream fullTopic=/sys/${Gateway productKey}/${Gateway deviceName}/app/down/thing/properties
                if (fullTopic.endsWith(topic)) {
                    // topic 即为 fullTopic 中业务方的区段，而不包含公用区段。
                    // 如果该 topic 需要处理，返回 true 后 onCommand 才会回调
                    return true;
                }
            }

            return false;
        }
    };

    final IMobileSubscrbieListener mobileSubscrbieListener = new IMobileSubscrbieListener() {
        @Override
        public void onSuccess(String fullTopic) {
            ALog.d(AliLiving.TAG, "subscribe onSuccess, fullTopic=" + fullTopic);
// with subscribe('/thing/properties')
// subscribe onSuccess, fullTopic=/sys/${Gateway productKey}/${Gateway deviceName}/app/down/thing/properties

            if (fullTopics.contains(fullTopic)) {
                return;
            } else {
                if (fullTopics.size() == 0) {
                    MobileChannel.getInstance().unRegisterDownstreamListener(mobileDownstreamListener);
                    MobileChannel.getInstance().registerDownstreamListener(true, mobileDownstreamListener);
                }

                fullTopics.add(fullTopic);
            }

            JSONObject json = new JSONObject();
            try {
                json.put("state", "successful");
                json.put("fullTopic", fullTopic);
                socketEvent.onEvent("subscribeState", json);
            } catch (JSONException e) {
                socketEvent.onError("error", e);
            }
        }

        @Override
        public void onFailed(String fullTopic, AError aError) {
            ALog.d(AliLiving.TAG, "subscribe onFailed, fullTopic=" + fullTopic);
            JSONObject json = new JSONObject();
            try {
                json.put("state", "failed");
                json.put("fullTopic", fullTopic);
                socketEvent.onEvent("subscribeState", json);
            } catch (JSONException e) {
                socketEvent.onError("error", e);
            }
        }

        @Override
        public boolean needUISafety() {
            return false;
        }
    };

    final IMobileSubscrbieListener mobileUnSubscrbieListener = new IMobileSubscrbieListener() {
        @Override
        public void onSuccess(String fullTopic) {
            ALog.d(AliLiving.TAG, "unsubscribe onSuccess, fullTopic=" + fullTopic);

            if (fullTopics.contains(fullTopic)) {
                fullTopics.remove(fullTopic);
            } else {
                return;
            }

            if (fullTopics.size() == 0) {
                MobileChannel.getInstance().unRegisterDownstreamListener(mobileDownstreamListener);
            }
        }

        @Override
        public void onFailed(String fullTopic, AError aError) {
            ALog.d(TAG, "unsubscribe onFailed, fullTopic=" + fullTopic);
        }

        @Override
        public boolean needUISafety() {
            return false;
        }
    };

    // 关闭长连接
    public void stopAliSocketListener(final Promise promise) {
        // for (String fullTopic : fullTopics) {
        //     TODO: convert fullTopic to topic
        //     MobileChannel.getInstance().unSubscrbie(topic, mobileUnSubscrbieListener);
        // }

        MobileChannel.getInstance().unRegisterDownstreamListener(mobileDownstreamListener);

        MobileChannel.getInstance().unRegisterConnectListener(mIMobileConnectListener);

        //TODO: use "/account/unbind" like in ios/AliLiving/WebSocket/WebSocketClient.m ?
        promise.resolve('1');
    }

    // 获取长连接连接状态
    public MobileConnectState getAliSocketListenerState() {
        return MobileChannel.getInstance().getMobileConnectState();
    }

    // 对 topic 进行订阅
    public void subscribe(String topic, final EventListener event) {
        if (socketEvent == null) {
            socketEvent = event;
        }

        MobileChannel.getInstance().subscrbie(topic, mobileSubscrbieListener);
    }

    // 对 topic 取消订阅
    public void unsubscribe(String topic) {
        MobileChannel.getInstance().unSubscrbie(topic, mobileUnSubscrbieListener);
    }

    // 在 topic 上发布消息
    public void ayncSendPublishRequest(final String topic, final JSONObject params, final Promise promise) {
        MobileChannel.getInstance().ayncSendPublishRequest(topic, params, new IMobileRequestListener() {
            @Override
            public void onSuccess(String jsonData) {
                ALog.d(AliLiving.TAG, "ayncSendPublishRequest onSuccess, rsp=" + jsonData);
                promise.resolve(jsonData);
            }

            @Override
            public void onFailure(AError error) {
                ALog.d(AliLiving.TAG, "ayncSendPublishRequest onFailure");
                promise.reject(new Exception("ayncSendPublishRequest onFailure"));
            }
        });
    }

    // 获取账户验证信息
    public void getAccountCredential(final Promise promise){

    }

    // 获取账号信息
    public void getCurrentAccountMessage(final Promise promise) throws JSONException {
        Map<String,Object> param = new com.alibaba.fastjson.JSONObject();
        param = OpenAccountSDK.getService(OpenAccountService.class).getSession().getOtherInfo();
        if (param == null) {
            promise.reject(new Exception("not login?"));
            return;
        }
        Log.d(AliLiving.TAG, "==========----------++++"+param.get("openaccount_other_info").toString());
        Map<String,Object> userInfo = (Map<String, Object>) param.get("openaccount_other_info");
        Log.d(AliLiving.TAG, userInfo.toString());
        JSONObject data = new JSONObject();
        data.putOpt("mobile", userInfo.get("mobile"));
        data.putOpt("email", userInfo.get("email"));
        promise.resolve(JsonConvert.jsonToReact(data));
    }

    public void send(String path, Map parmas, String version, boolean needAuth, IoTCallback callback) {
        IoTRequestBuilder builder = new IoTRequestBuilder()
                .setScheme(Scheme.HTTPS) // 设置Scheme方式，取值范围：Scheme.HTTP或Scheme.HTTPS，默认为Scheme.HTTPS
                .setPath(path) // 参考业务API文档，设置path
                .setApiVersion(version) // 参考业务API文档，设置apiVersion
                .setParams(parmas); // 参考业务API文档，设置API接口的参数，也可以使用.addParam(String key, String value)来设置
        if (needAuth) {
            builder.setAuthType("iotAuth"); // 当云端接口需要用户身份鉴权时需要设置该参数，反之则不需要设置
        }
        IoTRequest request = builder.build();
        // 获取Client实例，并发送请求
        IoTAPIClient ioTAPIClient = new IoTAPIClientFactory().getClient();

        ioTAPIClient.send(request, callback);
    }
}
