//
//  AliLiving.m
//  AliLiving
//
//  Created by 初程程 on 2019/4/9.
//  Copyright © 2019年 初程程. All rights reserved.
//

#import "AliLiving.h"
#import "IMSIotAuth.h"
#import "IMSOpenAccount.h"
#import "FYSDK.h"
#import "DiscoveryType.h"
#import "RNSendToJsReact.h"
#import "WebSocketClient.h"
#import "IMSLifeClient.h"
#import "IMSNetWorkServer.h"
#import <React/RCTBridge.h>
#import <IMSApiClient/IMSConfiguration.h>
#import <IMSAccount/IMSAccountService.h>
#import <IMSAuthentication/IMSAuthentication.h>
#import <React/RCTUtils.h>
#import <ALBBOpenAccountCloud/ALBBOpenAccountSDK.h>
#import <IMSIotSmart/IMSIotSmart.h>
#import <IMSIotSmart/IMSIotSmart+options.h>
#import <IMSIotSmart/IMSIotSmart+scope.h>
#import <IMSLog/IMSLog.h>

#import "../IMSOpenAccountCustom/IMSOpenAccountCustom.h"

#define kLoginError @"50001"
#define JK_IS_STR_NIL(objStr) (![objStr isKindOfClass:[NSString class]] || objStr == nil || [objStr length] <= 0)

@interface AliLiving()<RCTBridgeModule>
@end
@implementation AliLiving
RCT_EXPORT_MODULE(UgenAliLiving);

- (NSArray<NSString *> *)supportedEvents {
    return @[
        @"LoginSuceess",
        @"onReady",
        kOnPreCheck,
        kOnProvisionPrepare,
        kOnProvisioning,
        kOnProvisionStatus,
        kOnProvisionedResult,
        kError,
        kScanLocationDevice,
        kListenerSuccess,
        kListenerError,
        kNotifySuccess,
        kNotifyError,
        kBLEScan,
        kSokectBack,
        kAppExpConnectStateChange,

        kBluetoothEnabled,
        kBluetoothDisabled,
        kSystemLocationEnabled,
        kSystemLocationDisabled,
        kServiceConnected,
        kServiceDisconnected,
        kNotificationOnlineStatus,
        kNotificationGetDeviceState,
        kNotificationVendorResponse,
        kNotificationDataGetOnOff,
        kNotificationDataGetLevel,
        kNotificationDataGetLightness,
        kNotificationDataGetCtl,
        kNotificationDataGetTemp,
        kNotificationDataGetVersion,
        kNotificationDataGetMeshOtaProgress,
        kNotificationDataGetMeshOtaApplyStatus,
        kNotificationDataGetMeshOtaFirmwareDistributionStatus,
        kNotificationDataGetOtaState,
        kNotificationDataSetOtaModeRes,
        kDeviceStatusConnecting,
        kDeviceStatusConnected,
        kDeviceStatusLogining,
        kDeviceStatusLogin,
        kDeviceStatusLogout,
        kDeviceStatusErrorAndroidN,
        kDeviceStatusUpdateMeshCompleted,
        kDeviceStatusUpdatingMesh,
        kDeviceStatusUpdateMeshFailure,
        kDeviceStatusUpdateAllMeshCompleted,
        kDeviceStatusGetLtkCompleted,
        kDeviceStatusGetLtkFailure,
        kDeviceStatusMeshOffline,
        kDeviceStatusMeshScanCompleted,
        kDeviceStatusMeshScanTimeout,
        kDeviceStatusOtaMasterProgress,
        kDeviceStatusOtaMasterComplete,
        kDeviceStatusOtaMasterFail,
        kDeviceStatusGetFirmwareCompleted,
        kDeviceStatusGetFirmwareFailure,
        kDeviceStatusDeleteCompleted,
        kDeviceStatusDeleteFailure,
        kLeScan,
        kLeScanCompleted,
        kLeScanTimeout,
        kMeshOffline,
        kSaveOrUpdateJS,
    ]; //这里返回的将是你要发送的消息名的数组。
}

+ (void)InitializeSmartliving:(UIApplication *)application launchOptions:(NSDictionary *)launchOptions {
    // 1、提供 debug 调试功能，支持切换安全图片，serverEnv、boneEnv 外部客户请默认 release
    NSString *authCode;
    NSString *serverEnv;
    NSString *boneEnv;
#if __has_include(<IMSDebug/IMSDebug.h>)
    NSDictionary *dict = [[IMSDebugEnv sharedInstance] reSetDebugDict];
    authCode = dict[@"authCode"];
    serverEnv = dict[@"serverEnv"];
    boneEnv = dict[@"boneEnv"];
#else
    authCode = @"product";
    serverEnv = @"release";
    boneEnv = @"release";
#endif

    // 2、设置在控制台显示日志
    // 统一设置所有模块的日志 tag 输出级别
    [IMSLog setAllTagsLevel:IMSLogLevelVerbose];
    // 可选：设置是否开启日志的控制台输出，建议在 release 版本中不要开启。
    [IMSLog showInConsole:YES];
    // sdk demo 中的 TODO，估计没啥用: 修改调用时机，放日志 Demo 初始化
//    __block IMSDashboardLogAssistant * assistant = [[IMSDashboardLogAssistant alloc]init];
//    assistant.tagWhiteList = @[];
//    [IMSLog addAssistant:assistant];
//    double delayInSeconds = 2.0;
//    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
//    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//        [assistant restoreTagLevelRules];
//    });

    // 3、IMSSmartSDK 初始化：regionType
    IMSIotSmartConfig *config = [IMSIotSmartConfig new];
    config.regionType = REGION_ALL; // 取值范围参见枚举类型 `IMSRegionType`
    [[IMSIotSmart sharedInstance] setConfig:config];
    // 设置安全图片。如果不设置，默认使用 china_production
    // [[IMSIotSmart sharedInstance] setAuthCode:@"china_production"];

    IMSIotSmartEnvironment *env = [[IMSIotSmartEnvironment alloc] init];
    env.serverEnv = serverEnv;
    env.boneEnv = boneEnv;
    [[IMSIotSmart sharedInstance] setEnvironment:env];
    [[IMSIotSmart sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions]; // 必须要此语句，否则登陆窗口显示不出来，甚至连打印信息也出不来

    // 4、支持OASDK设置多语言
    // 设置 OA 模块多语言:设置语言前缀：de、en、es、fr、ja、ko、ru、zh、hi、it、pt、pl、nl
    NSString *language = [IMSIotSmart sharedInstance].getLanguage;
    [[IMSiLopOALanguageManage shareInstance] setOpenAccountModuleLanguageWithLanguagePrefix:[language substringToIndex:2]];

    // 配置 APP 上能看到的产品的范围
    // PRODUCT_SCOPE_ALL：表示当前项目中已发布和未发布的所有产品
    // PRODUCT_SCOPE_PUBLISHED：表示只包含已发布产品
    // 正式发布的 APP 请选择 PRODUCT_SCOPE_PUBLISHED
    [[IMSIotSmart sharedInstance] configProductScope:PRODUCT_SCOPE_ALL];
}

/**
 * 获取设备状态
 */
- (void) getStatus:(NSString *)iotId {
    IMSThing *panelDevice = self.panelDevices[iotId];
    if (panelDevice != nil) {
        [[panelDevice getThingActions] getStatus:^(IMSThingActionsResponse * _Nullable response) {
            NSLog(@"AliLiving statusCallback isSuccess->%d data->%@", response.success, response.dataObject);
// data->{
//     "code": 200,
//     "data": {
//         "time": 1604976420650,
//         "status": 1
//     }
// }

            if (response.success) {
                NSData *jsonData = [NSJSONSerialization dataWithJSONObject:response.dataObject options:0 error:0];
                NSString *dataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
                NSDictionary *map = @{
                    @"meshAddress":iotId,
                    @"opcode":@"getStatus",
                    @"params":dataStr,
                };
                [self sendEventWithName:kNotificationVendorResponse body:map];
            }
        }];
    }
}

/**
 * 获取设备属性
 */
- (void) getProperties:(NSString *)iotId {
    IMSThing *panelDevice = self.panelDevices[iotId];
    if (panelDevice != nil) {
        [[panelDevice getThingActions] getPropertiesFull:^(IMSThingActionsResponse * _Nullable response) {
            NSLog(@"AliLiving getPropsCallBack isSuccess->%d data->%@", response.success, response.dataObject);
// // from online router
// isSuccess->true
// data->{
//     "data": {
//         "CountDownList": {
//             "time": 1604371244935,
//             "value": {}
//         },
//         "PowerSwitch": {
//             "time": 1604967137081,
//             "value": 1
//         },
//         "LocalTimer": {
//             "time": 1604371244935,
//             "value": []
//         },
//         "CountDown": {
//             "time": 1604371244935,
//             "value": {}
//         }
//     }
// }

// // from offline router
// isSuccess->true
// data->{
//     "data": {
//         "CountDownList": {
//             "time": 0,
//             "value": {
//                 "Target": "PowerSwitch",
//                 "Contents": "",
//                 "PowerSwitch": 0
//             }
//         },
//         "PowerSwitch": {
//             "time": 0,
//             "value": 1
//         },
//         "LocalTimer": {
//             "time": 0,
//             "value": []
//         }
//     }
// }

            if (response.success) {
                NSData *jsonData = [NSJSONSerialization dataWithJSONObject:response.dataObject options:0 error:0];
                NSString *dataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
                NSDictionary *map = @{
                    @"meshAddress":iotId,
                    @"opcode":@"getProperties",
                    @"params":dataStr,
                };
                [self sendEventWithName:kNotificationVendorResponse body:map];
            }
        }];
    }
}

RCT_EXPORT_METHOD(getProperties:(NSString *)iotId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    IMSThing *panelDevice = self.panelDevices[iotId];
    if (panelDevice != nil) {
        [[panelDevice getThingActions] getPropertiesFull:^(IMSThingActionsResponse * _Nullable response) {
            NSLog(@"AliLiving getPropsCallBack promise isSuccess->%d data->%@", response.success, response.dataObject);
            if (response.success) {
                NSData *jsonData = [NSJSONSerialization dataWithJSONObject:response.dataObject options:0 error:0];
                NSString *dataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
                NSDictionary *map = @{
                    @"meshAddress":iotId,
                    @"opcode":@"getProperties",
                    @"params":dataStr,
                };

                resolve(map);
            } else {
                reject(@"", @"getProperties isSuccess->false", response.responseError);
            }
        }];
    } else {
        reject(@"", @"getProperties no such device", nil);
    }
}

/**
 * 设置设备属性
 */
RCT_EXPORT_METHOD(setProperties:(NSString *)iotId params:(NSString *)params) {
//params 格式参考如下：
/*
{
"items":{
    "PowerSwitch": 0
},
"iotId":"s66CDxxxxXH000102"
}
*/
    NSLog(@"AliLiving setProperties params->%@", params);
    IMSThing *panelDevice = self.panelDevices[iotId];
    if (panelDevice != nil) {
        if (params == nil) {
            return;
        }
        NSData *jsonData = [params dataUsingEncoding:NSUTF8StringEncoding];
        NSError *err;
        NSDictionary *paramsDict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                            options:NSJSONReadingMutableContainers
                                                              error:&err];
        if(err) {
            return;
        }

        [[panelDevice getThingActions] setProperties:paramsDict[@"items"] responseHandler:^(IMSThingActionsResponse * _Nullable response) {
            NSLog(@"AliLiving setPropsCallBack isSuccess->%d data->%@", response.success, response.dataObject);
// data->{
//     "data": {}
// }

            // 因为上面已经 subAllEvents ，使得每次设置属性时都会
            // 有包含属性的事件返回了，所以这里没必要多取一次属性
            // if (response.success) {
            //     [self getProperties:iotId];
            // }
        }];
    }
}

/**
 * 调用服务
 */
RCT_EXPORT_METHOD(invokeService:(NSString *)iotId params:(NSString *)params) {
//params 格式参考如下
/*
{
"args":{
    "Saturation":80,
    "LightDuration":50,
    "Hue":325,
    "Value":50
},
"identifier":"Rhythm",
"iotId":"s66CDxxxxItXH000102"
}
*/
    NSLog(@"AliLiving setProperties params->%@", params);
    IMSThing *panelDevice = self.panelDevices[iotId];
    if (panelDevice != nil) {
        if (params == nil) {
            return;
        }
        NSData *jsonData = [params dataUsingEncoding:NSUTF8StringEncoding];
        NSError *err;
        NSDictionary *paramsDict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                            options:NSJSONReadingMutableContainers
                                                              error:&err];
        if(err) {
            return;
        }

        [[panelDevice getThingActions] invokeService:paramsDict[@"identifier"] params:paramsDict[@"args"] responseHandler:^(IMSThingActionsResponse * _Nullable response) {
            NSLog(@"AliLiving invokeServiceCallBack isSuccess->%d data->%@", response.success, response.dataObject);
            if (response.success) {
            }
        }];
    }
}

/**
 * 订阅所有事件
 */
- (void)subAllEvents:(NSString *)iotId {
    IMSThing *panelDevice = self.panelDevices[iotId];
    DeviceObserver *deviceObserver = self.deviceObservers[iotId];
    if (panelDevice != nil && deviceObserver != nil) {
        [panelDevice registerThingObserver:deviceObserver];
    }
}

- (void)insertDevice:(NSString *)iotId {
    NSLog(@"AliLiving insertDevice %@", iotId);
    IMSThing *panelDevice = self.panelDevices[iotId];
    if (panelDevice == nil) {
        IMSThing *panelDevice = [kIMSThingManager buildThing:iotId];
        [self.panelDevices setObject:panelDevice forKeyedSubscript:iotId];
        DeviceObserver *deviceObserver = [[DeviceObserver alloc]MyInit:iotId rnModule:self];
        [self.deviceObservers setObject:deviceObserver forKeyedSubscript:iotId];

        [self getStatus:iotId];
        // [self getProperties:iotId]; // ref the comment in getNodesProperties() of index.native.js
        [self subAllEvents:iotId];
    }
}

RCT_EXPORT_METHOD(removeDevice:(NSString *)iotId) {
    NSLog(@"AliLiving removeDevice %@", iotId);
    DeviceObserver *deviceObserver = self.deviceObservers[iotId];
    IMSThing *panelDevice = self.panelDevices[iotId];
    if (panelDevice != nil) {
        [self.panelDevices removeObjectForKey:iotId];

        if (deviceObserver != nil) {
            [panelDevice unregisterThingObserver:deviceObserver];
        }

        [kIMSThingManager destroyThing:panelDevice];
    }

    if (deviceObserver != nil) {
        [self.deviceObservers removeObjectForKey:iotId];
    }
}

RCT_EXPORT_METHOD(setDevices:(NSArray *)devices) {
    for (NSDictionary *device in devices) {
        NSString *iotId = device[@"meshAddress"];
        if (iotId) {
            [self insertDevice:iotId];
        }
    }
}

//初始化
RCT_EXPORT_METHOD(doInit) {
//    if (![IMSAccountService sharedService].accountProvider) {
//        [IMSConfiguration initWithHost:@"api.link.aliyun.com" serverEnv:IMSServerRelease];
//
//        IMSOpenAccount *openAccount = [IMSOpenAccount sharedInstance];
//
//        [IMSAccountService sharedService].accountProvider = openAccount;
//
//        [IMSAccountService sharedService].sessionProvider = openAccount;
//
//        [IMSIotAuth auth];
//    }

    NSLog(@"AliLiving doInit");
    self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    __weak FYSDK *sdk = [FYSDK sharedInstance];
    sdk.mRnModule = self;

    [IMSLifeClient sharedClient].mRnModule = self;

    self.panelDevices = [[NSMutableDictionary alloc] init];
    self.deviceObservers = [[NSMutableDictionary alloc] init];

    [self sendEventWithName:kDeviceStatusLogout body:nil];

    if ([[IMSOpenAccount sharedInstance] isLogin]) {
        [self sendEventWithName:kServiceConnected body:nil];
    } else {
        IMSIotCountry *mSelectedCountry = [[IMSIotSmart sharedInstance] getCountry];
        if (mSelectedCountry == nil) {
            IMSIotCountry *mSelectedCountry = [[IMSIotCountry alloc] init];

//            mSelectedCountry.areaName = @"中国大陆";
//            mSelectedCountry.code = @"86";
//            mSelectedCountry.domainAbbreviation = @"CN";
//            mSelectedCountry.isoCode = @"CHN";
//            mSelectedCountry.pinyin = @"ZhongGuoDaLu";
//
//            mSelectedCountry.areaName = @"美国";
//            mSelectedCountry.code = @"1";
//            mSelectedCountry.domainAbbreviation = @"US";
//            mSelectedCountry.isoCode = @"USA";
//            mSelectedCountry.pinyin = @"MeiGuo";

            mSelectedCountry.areaName = @"德国"; // 为防止哪天美国佬又发疯搞服务器限制，还是默认定位在德国以便使用阿里生活物联网平台的德国服务器吧
            mSelectedCountry.code = @"49";
            mSelectedCountry.domainAbbreviation = @"DE";
            mSelectedCountry.isoCode = @"DEU";
            mSelectedCountry.pinyin = @"DeGuo";

            [[IMSIotSmart sharedInstance] setCountry:mSelectedCountry callback:^(BOOL needRestartApp) {
                if (needRestartApp) {
                    NSLog(@"AliLiving %@ CountrySet default needRestartApp", mSelectedCountry.areaName);
                } else {
                    NSLog(@"AliLiving %@ CountrySet default", mSelectedCountry.areaName);
                }
                [self startLogin];
            }];
        } else {
            NSLog(@"AliLiving %@ getCountry", mSelectedCountry.areaName);
            [self startLogin];
        }
    }
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    //第一次打开或者每次蓝牙状态改变都会调用这个函数
    if (central.state == CBCentralManagerStatePoweredOn) {
        NSLog(@"Bluetooth was enabled");
        [self sendEventWithName:kBluetoothEnabled body:nil];
     } else {
         [self sendEventWithName:kBluetoothDisabled body:nil];
         NSLog(@"Bluetooth was disabled");
   }
}
RCT_EXPORT_METHOD(enableBluetooth) {
    NSLog(@"AliLiving enableBluetooth");
}

- (void)startLogin {
    UIViewController *con = RCTKeyWindow().rootViewController;

    id<ALBBOpenAccountUIService> uiService = ALBBService(ALBBOpenAccountUIService);
    [uiService presentLoginViewController:con success:^(ALBBOpenAccountSession *currentSession) {
        [self sendEventWithName:kServiceConnected body:nil];
        NSLog(@"AliLiving onLoginSuccess");
    } failure:^(NSError *error) {
        NSLog(@"AliLiving onLoginFailed %@", error.domain);
    }];
}

//登录
RCT_REMAP_METHOD(login, resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)rejecter){
    UIViewController *con = (UIViewController *)[[UIApplication sharedApplication] keyWindow].rootViewController;

    [[IMSOpenAccount sharedInstance] showLoginWithController:con success:^(NSDictionary *response) {
        [IMSIotAuth checkToken];
        resolve(response);
    } failure:^(NSError *error) {
        rejecter(kLoginError,error.domain,error);
    }];
}
//自有登录
RCT_REMAP_METHOD(ssoLogin,authCode:(NSString *)authCode ssoResolve:(RCTPromiseResolveBlock)resolve ssoRejecter:(RCTPromiseRejectBlock)rejecter){

    [IMSOpenAccount sharedInstance].thirdLoginResult = ^(NSError *err, NSDictionary *session) {
        if (err) {
            rejecter(kLoginError,err.domain,err);
        }else{
            resolve(session);
        }
    };

    [[IMSOpenAccount sharedInstance] thirdLoginWithAuthCode:authCode];
}
//退出登录
RCT_EXPORT_METHOD(logout:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)rejecter){
    [[IMSOpenAccount sharedInstance] logout];
    if ([[IMSOpenAccount sharedInstance] isLogin]) {
        rejecter(@"100001",@"退出登录失败",nil);
    }else{
        resolve(@"sucess");
    }
}
//登录状态判断
RCT_EXPORT_METHOD(isLogin:(RCTPromiseResolveBlock)resolve isLoginRejecter:(RCTPromiseRejectBlock)rejecter){
    BOOL result = [[IMSOpenAccount sharedInstance] isLogin];
    if(result) {
        resolve(@true);
    }else{
        resolve(@false);
    }
}
//开始搜寻设备
RCT_EXPORT_METHOD(startScanLocalDevice:(BOOL)unclaimed){
    NSLog(@"AliLiving startScanLocalDevice unclaimed %@", unclaimed ? @"true" : @"false");
//  阿里官方文档中对 filterParams 这个变量并没有详细说明，只从官方 demo 中搜到了
//  @{@"deviceType":@[@"breeze"]} 的字眼，询问后阿里的人员只说与 Android 的
//  LocalDeviceMgr.getInstance().startDiscovery 中 enumSet 参数用来过滤
//  返回设备的作用并不相同因而没有给我其他数组元素，我自己实测下来也发现不论 filterParams
//  是否 nil ，都能返回未配网的蓝牙设备和已配网的蓝牙设备，所以这里干脆都给 nil 吧
//    NSDictionary *filterParams = unclaimed ? @{@"deviceType":@[@"breeze"]} : nil;
    NSDictionary *filterParams = unclaimed ? nil : nil;
    [[FYSDK sharedInstance] startScanLocalDevice:^(NSDictionary * _Nonnull deviceDict, NSError * _Nonnull err) {
        if (err) {
            [self sendEventWithName:kError body:@{@"message":err.domain,@"code":@"500"}];
        } else {
            [self sendEventWithName:kLeScan body:deviceDict];
        }
    }  filterParams:filterParams unclaimed:unclaimed];
}
//停止查找设备
RCT_EXPORT_METHOD(stopScanLocalDevice){
    [[FYSDK sharedInstance] stopScanLocalDevice];
}
//添加配网设备
RCT_EXPORT_METHOD(startAddDevice:(NSString *)macAddress productKey:(NSString *)productKey discoveryType:(NSInteger)discoveryType cfg:(NSDictionary *)cfg resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject){
    __weak FYSDK *sdk = [FYSDK sharedInstance];

    NSString *ssid = [cfg objectForKey:@"newName"];
    NSString *password = [cfg objectForKey:@"newPwd"];

    sdk.provisioningBlock = ^{
        // 配网中
        NSLog(@"AliLiving startAddDevice onProvisioning");
    };

    sdk.provisionPrepareBlock = ^(NSInteger prepareType) {
        NSLog(@"AliLiving startAddDevice onProvisionPrepare prepareType->%ld", (long)prepareType);

        if (prepareType == LKPGuideCodeOnlyInputPwd) {
            // 一键配网、蓝牙辅助配网、设备热点配网、二维码配网、手机热点配网会走到该流程
            // 之后调用 toggleProvision 接口开始配网

            NSDictionary *params = @{
                @"status":@"ConfigingWiFi",
            };
            [self sendEventWithName:kDeviceStatusUpdatingMesh body:params];

            [sdk toggleProvisionWithName:ssid wifiPassword:password timeout:60];
        } else if (prepareType == LKPGuideCodeWithUserGuide) {
           // 手机热点配网时可能会走到该流程以便提示用户开启手机热点
        } else if (prepareType == LKPGuideCodeWithUserGuideForSoftAp) {
        } else if (prepareType == LKPGuideCodeWithUserGuideForQR) {
        }
    };
    sdk.preCheckBlock = ^(BOOL success, NSError *err) {
        // 参数检测回调
        NSLog(@"AliLiving startAddDevice onPreCheck %hhd %@", success, err);
//        if (err) {
//            [self sendEventWithName:kError body:@{}];
//        }else{
//            [self sendEventWithName:kOnProvisionedResult body:@{@"state":kOnPreCheck,@"result":@""}];
//        }
    };

    sdk.provisionedResultBlock = ^(IMLCandDeviceModel *candDeviceModel, NSError *err) {
        // 处理配网结果，如果配网成功后包含 token ，请使用配网成功带的 token 做绑定。
        NSLog(@"AliLiving toogle provisionedResultBlock candDeviceModel:%@ NSError:%@", candDeviceModel, err);
// why there is no iotId and fwVersion and token?
//candDeviceModel:{
//    cipherRandomStr = 00000000000000000000000000000000;
//    cipherType = 0;
//    devType = "ble_subtype_3";
//    deviceIsReset = 0;
//    deviceName = testDeviceName2;
//    enableGlobalCloudToken = 0;
//    ignoreLocationPermisionCheck = 0;
//    isBinded = 0;
//    linkType = 0;
//    mac = "BC:DF:20:71:74:04";
//    productKey = a17hN4W4777;
//    regionNode = 0;
//    softApNoNeedSwitchBackRouter = 0;
//}

        [sdk stopToogle];

        if (candDeviceModel) {
            NSLog(@"AliLiving toogle comboDeviceStartDistributionNetwork success");
//            NSString *token = JK_IS_STR_NIL(candDeviceModel.token)?@"":candDeviceModel.token;
            resolve(@{
                @"meshAddress":candDeviceModel.iotId ?: sdk.iotId,
                @"nodeInfo":@{@"v":candDeviceModel.fwVersion ?: @""},
            });

            [self insertDevice:sdk.iotId];
//            [sdk notifyWiFiStatus:sdk.iotId status:DeviceWifiStatus_Set];
        } else {
            NSLog(@"AliLiving toogle comboDeviceStartDistributionNetwork failure");
// AliLiving toogle comboDeviceStartDistributionNetwork provisionError Error Domain=com.alibaba.IMSDeviceCenter Code=101616 "ble disconnected" UserInfo={subcode=61601, NSLocalizedDescription=ble disconnected}
            if (err.code == 101616) {
                // 对于蓝牙和 WiFi 双模 combo 设备来说，阿里官方测下来说是如果同时开启蓝牙和 WiFi ，对导致他们互相干扰而效果不好，
                // 所以从设备 SDK 1.6.6 开始阿里官方已经不支持 combo 设备配网。而在仍然使用设备 SDK 1.6.2 的情况下，模块厂商说
                // 可以在设备代码 Living_SDK/framework/bluetooth/breeze/api/breeze_export.c 的 case BZ_EVENT_APINFO
                // 那里调用 breeze_awss_stop() 也就是配网成功后就关掉蓝牙，只是这个会造成 iOS 这里出现 ble disconnected 的
                // 错误（Android 不知为何不受影响），所以这里折衷一下，将 ble disconnected 类型的错误也当作成功来处理。
                NSLog(@"AliLiving toogle comboDeviceStartDistributionNetwork success despite ble disconnected");
                resolve(@{
                    @"meshAddress":sdk.iotId,
                    @"nodeInfo":@{@"v":@""},
                });

            [self insertDevice:sdk.iotId];
//                [sdk notifyWiFiStatus:sdk.iotId status:DeviceWifiStatus_Set];
            } else {
                NSLog(@"AliLiving toogle comboDeviceStartDistributionNetwork failure except ble disconnected");
                reject(@"", @"toogle comboDeviceStartDistributionNetwork failure", err);

//                [sdk notifyWiFiStatus:sdk.iotId status:DeviceWifiStatus_NotSet];
            }
        }
    };

    NSLog(@"AliLiving claiming %@ %@", macAddress, [DiscoveryType getValue:discoveryType]);

    if (discoveryType == DISCOVERY_COMBO_SUBTYPE_0X03_DEVICE) {
        sdk.provisionStatusPhoneApBlock = ^() {};
        sdk.provisionStatusSoftApBlock = ^(int status, NSDictionary *dic) {};
        sdk.provisionStatusQRBlock = ^(NSString *qrcode) {};

        sdk.provisionStatusBleConfigBlock = ^(int status, NSDictionary *dic) {
            NSLog(@"AliLiving startAddDevice onProvisionStatus %d", status);
            if (status == 2 && dic != nil) {
                NSLog(@"AliLiving BLE_DEVICE_SCAN_SUCCESS %@", dic);
                NSString *devType = dic[@"devType"];
                NSLog(@"AliLiving devType->%@ bleMac->%@ prouctID->%@", devType, dic[@"mac"], dic[@"productId"]);
                if ([devType isEqualToString:@"ble_subtype_3"]) {
                    // 让底层 SDK 继续配网，目前业务暂时不用传入任何参数
                    [kLkAddDevBiz continueProvision:nil];
                }
            }
        };

        [sdk breezeSubDevLogin:productKey macAddress:macAddress ssid:ssid password:password resolver:resolve rejecter:reject];
    } else {
        NSLog(@"AliLiving not debug yet with this discoveryType");
        reject(@"", @"not debug yet with this discoveryType", nil);
        // [sdk.wifiConnect:macAddress iotId:null ssid:ssid password:password resolver:resolve rejecter:reject];
    }
}
//中止添加设备配网流程
RCT_EXPORT_METHOD(stopAddDevice){
    [[FYSDK sharedInstance] stopAddDevice];
}
//添加配网的wifi名和wifi密码
RCT_REMAP_METHOD(toggleProvision,wifiName:(NSString *)wifiName wifiPassword:(NSString *)wifiPassword timeout:(NSString *)timeout){
    [[FYSDK sharedInstance] toggleProvisionWithName:wifiName wifiPassword:wifiPassword timeout:[timeout intValue]];
}
//获取设备token
RCT_REMAP_METHOD(getDeviceToken,pk:(NSString *)pk dn:(NSString *)dn timeout:(NSString *)timeout getTokenResolve:(RCTPromiseResolveBlock)resolve getTokenRejecter:(RCTPromiseRejectBlock)rejecter){
    __block BOOL isBack = NO;
    [[FYSDK sharedInstance] getDeviceTokenWithProductKey:pk deviceName:dn timeout:timeout.integerValue block:^(NSString * _Nonnull token) {
        if (!JK_IS_STR_NIL(token)) {
            if (!isBack) {
                isBack = YES;
                resolve(token);
            }
        }else{
            if (!isBack) {
                isBack = YES;
                rejecter(@"567",@"token获取失败",nil);
            }
        }
    }];
}

RCT_REMAP_METHOD(startAliSocketListener, startResolve:(RCTPromiseResolveBlock)resolve startRejecter:(RCTPromiseRejectBlock)rejecter) {
    [WebSocketClient sharedInstance].listenerBlock = ^(NSError *err) {
        if (err) {
            rejecter(@"startAliSocketListener", @"bindAccount failure", nil);
        } else {
            resolve(@"1");
        }
    };
    [[WebSocketClient sharedInstance] startListener];
}

RCT_REMAP_METHOD(stopAliSocketListener, stopResolve:(RCTPromiseResolveBlock)resolve stopRejecter:(RCTPromiseRejectBlock)rejecter) {
    [[WebSocketClient sharedInstance] stopListener:^(BOOL isSuccess) {
        resolve(isSuccess ? @"1" : @"0");
    }];
}

RCT_REMAP_METHOD(getAliSocketListenerState,stateResolve:(RCTPromiseResolveBlock)resolve stateRejecter:(RCTPromiseRejectBlock)rejecter) {
    BOOL isOpen = [[WebSocketClient sharedInstance] connectState];
    resolve(isOpen ? @"CONNECTED" : @"0");
}

RCT_EXPORT_METHOD(subscribe:(NSString *)topic) {
    [WebSocketClient sharedInstance].subscribeListenerBlock = ^(NSError *err) {
        if (err) {
            NSDictionary *map = @{
                @"state": @"failed",
                @"topic": topic,
            };
            [self sendEventWithName:kSubscribeState body:map];
        } else {
            NSDictionary *map = @{
                @"state": @"successful",
                @"topic": topic,
            };
            [self sendEventWithName:kSubscribeState body:map];
        }
    };
    [WebSocketClient sharedInstance].downstreamListenerBlock = ^(NSString *topic, NSString *data) {
            NSDictionary *map = @{
                @"data": data,
                @"topic": topic,
            };
            [self sendEventWithName:kSubscribeDownstream body:map];
    };
    [[WebSocketClient sharedInstance] subscribeTopic:topic];
}

RCT_EXPORT_METHOD(unsubscribe:(NSString *)topic) {
    [[WebSocketClient sharedInstance] cancelTopic:topic];
}

RCT_REMAP_METHOD(ayncSendPublishRequest, topic:(NSString *)topic params:(id)params publishResolve:(RCTPromiseResolveBlock)resolve publishRejecter:(RCTPromiseRejectBlock)rejecter) {
    [[WebSocketClient sharedInstance] publish:topic params:(id)params publishResolve:resolve publishRejecter:rejecter];
}

RCT_REMAP_METHOD(getCurrentAccountMessage,accountResolve:(RCTPromiseResolveBlock)resolve accountRejecter:(RCTPromiseRejectBlock)rejecter){
    NSDictionary *dict = [ALBBOpenAccountSession sharedInstance].getUser.openaccountInfoDict;
    if (dict == nil) {
        rejecter(@"123",@"not login?",nil);
        return;
    }
    NSLog(@"AliLiving openaccountInfoDict %@", dict);
    resolve(@{
        @"mobile": dict[@"mobile"] ?: @"",
        @"email": dict[@"email"] ?: @"",
    });
}
RCT_REMAP_METHOD(getAccountCredential,getAccountResolve:(RCTPromiseResolveBlock)resolve getAccountRejecter:(RCTPromiseRejectBlock)rejecter){
    IMSCredential *credential = [IMSCredentialManager sharedManager].credential;

    NSDictionary *credentialDict = @{
                                     @"identityId":credential.identityId,
                                     @"iotToken":credential.iotToken,
                                     @"iotRefreshToken":credential.iotRefreshToken
                                     };

    resolve(credentialDict);
}

//发送网络请求
RCT_REMAP_METHOD(send, path:(NSString *)path params:(id)params version:(NSString *)version iotAuth:(BOOL)iotAuth sendResolve:(RCTPromiseResolveBlock)resolve sendRejecter:(RCTPromiseRejectBlock)rejecter){

    NSData *data = [params dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

    [IMSNetWorkServer sendIotAuthRequestWithPath:path version:version params:dict handler:^(BOOL isSuccess, id response ,NSString *requestId) {
        if (isSuccess) {
            NSDictionary *dict =@{@"data":response};
            NSString *json = [self toJSONStringWithDict:dict];
            resolve(json);
        }else{
            NSError *error = (NSError *)response;
            rejecter([NSString stringWithFormat:@"%ld",(long)error.code], error.localizedFailureReason, error);
            if (error.code == 401) {
                NSLog(@"AliLiving RCT_REMAP_METHOD send(%@): not login or refresh iotToken failure", path);
                [[IMSOpenAccount sharedInstance] logout];
                [self startLogin];
            }
        }
    }];
}
//isWifi5G
RCT_REMAP_METHOD(isWifi5G,isFiveWifiResolve:(RCTPromiseResolveBlock)resolve isFiveWifiRejecter:(RCTPromiseRejectBlock)rejecter){
    //    resolve(YES);
}
- (NSString *)toJSONStringWithDict:(NSDictionary *)dict {
    NSData *data = [NSJSONSerialization dataWithJSONObject:dict
                                                   options:NSJSONReadingMutableLeaves | NSJSONReadingAllowFragments
                                                     error:nil];

    if (data == nil) {
        return nil;
    }

    NSString *string = [[NSString alloc] initWithData:data
                                             encoding:NSUTF8StringEncoding];
    return string;
}
//RCT_REMAP_METHOD(getWifiState,wifiResolve:(RCTPromiseResolveBlock)resolve wifiRejecter:(RCTPromiseRejectBlock)rejecter){
//    resolve([self getSignalStrengthBar]);
//}
//- (NSString *)getSignalStrengthBar {
//    if (![self whetherConnectedNetwork]) return @"";
//    UIApplication *app = [UIApplication sharedApplication];
//    NSArray *subviews = [[[app valueForKey:@"statusBar"] valueForKey:@"foregroundView"] subviews];
//    NSString *dataNetworkItemView = nil;
//    NSString *signalStrengthBars = @"";
//    for (id subview in subviews) {
//        if([subview isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]] && [[self getNetworkType] isEqualToString:@"WIFI"] && ![[self getNetworkType] isEqualToString:@"NONE"]) {
//            dataNetworkItemView = subview;
//            signalStrengthBars = [NSString stringWithFormat:@"0%@",[dataNetworkItemView valueForKey:@"_wifiStrengthBars"]];
//            break;
//        }
//        if ([subview isKindOfClass:[NSClassFromString(@"UIStatusBarSignalStrengthItemView") class]] && ![[self getNetworkType] isEqualToString:@"WIFI"] && ![[self getNetworkType] isEqualToString:@"NONE"]) {
//            dataNetworkItemView = subview;
//            signalStrengthBars = [NSString stringWithFormat:@"1%@",[dataNetworkItemView valueForKey:@"_signalStrengthBars"]];
//            break;
//        }
//    }
//    return signalStrengthBars;
//}
//- (NSString *)getNetworkType {
//    if (![self whetherConnectedNetwork]) return @"NONE";
//    UIApplication *app = [UIApplication sharedApplication];
//    NSArray *subviews = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
//    NSString *type = @"NONE";
//    for (id subview in subviews) {
//        if ([subview isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
//            int networkType = [[subview valueForKeyPath:@"dataNetworkType"] intValue];
//            switch (networkType) {
//                case 0:
//                    type = @"NONE";
//                    break;
//                case 1:
//                    type = @"2G";
//                    break;
//                case 2:
//                    type = @"3G";
//                    break;
//                case 3:
//                    type = @"4G";
//                    break;
//                case 5:
//                    type = @"WIFI";
//                    break;
//            }
//        }
//    }
//    return type;
//}
//- (BOOL)whetherConnectedNetwork
//{
//    //创建零地址，0.0.0.0的地址表示查询本机的网络连接状态
//
//    struct sockaddr_storage zeroAddress;//IP地址
//
//    bzero(&zeroAddress, sizeof(zeroAddress));//将地址转换为0.0.0.0
//    zeroAddress.ss_len = sizeof(zeroAddress);//地址长度
//    zeroAddress.ss_family = AF_INET;//地址类型为UDP, TCP, etc.
//
//    // Recover reachability flags
//    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
//    SCNetworkReachabilityFlags flags;
//
//    //获得连接的标志
//    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
//    CFRelease(defaultRouteReachability);
//
//    //如果不能获取连接标志，则不能连接网络，直接返回
//    if (!didRetrieveFlags)
//    {
//        return NO;
//    }
//    //根据获得的连接标志进行判断
//
//    BOOL isReachable = flags & kSCNetworkFlagsReachable;
//    BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
//    return (isReachable&&!needsConnection) ? YES : NO;
//}
- (dispatch_queue_t)methodQueue{
    return dispatch_get_main_queue();
}
- (instancetype)init
{
    self = [super init];
    if (self) {

    }
    return self;
}

@end


@implementation DeviceObserver
-(DeviceObserver*)MyInit:(NSString*)iotId rnModule:(AliLiving *)rnModule {
    mIotId = iotId;
    mRnModule = rnModule;
    return self;
}

- (void)onPropertyChange:(NSString *)iotId params:(NSDictionary *)data{
    NSLog(@"DeviceObserver onPropertyChange iotId->%@ data->%@", iotId, data);
// // after setProperties on APP, event from LAN
// iotId->vvssa4DEzVglIGxDl777000000
// data->{
//     "iotId": "vvssa4DEzVglIGxDl777000000",
//     "items": {
//         "PowerSwitch": {
//             "time": 1610417474327,
//             "value": 0
//         }
//     }
// }

    NSDictionary *items = data[@"items"];
    if (items != nil) {
        // use whitelist events to prevent slowing the APP performance
        // only keep PowerSwitch in whitelist, if add heart
        // beat with PowerSwitch, then even can remove
        // "/app/down/thing/properties" from whitelist
        if (items[@"PowerSwitch"] == nil) {
            return;
        }
    }

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:0];
    NSString *dataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSDictionary *map = @{
        @"meshAddress":mIotId,
        @"opcode":@"/app/down/thing/properties",
        @"params":dataStr,
    };
    [mRnModule sendEventWithName:kNotificationVendorResponse body:map];
}

- (void)onStatusChange:(NSString *)iotId params:(NSDictionary *)data {
    NSLog(@"DeviceObserver onStatusChange iotId->%@ data->%@", iotId, data);
// iotId->vvssa4DEzVglIGxDl777000000
// data->{
//     "status": {
//         "time": 1604985312231,
//         "value": 1
//     }
// }

// iotId->vvssa4DEzVglIGxDl777000000
// data->{
//     "groupIdList": [
//         {
//             "groupType": "ISOLATION",
//             "groupId": "a103ToHAxVJe1yaP"
//         }
//     ],
//     "netType": "NET_WIFI", // NET_LORA（表示LoRa）；NET_CELLULAR（表示2G/3G/4G/5G蜂窝网）；NET_WIFI（表示Wi-Fi）；NET_ZIGBEE（表示ZigBee）；NET_ETHERNET（表示以太网）；NET_OTHER（表示其他网络类型）
//     "activeTime": 1603673532205,
//     "ip": "112.17.177.241",
//     "aliyunCommodityCode": "iothub_senior",
//     "categoryKey": "light",
//     "nodeType": "DEVICE", // 设备的节点类型：DEVICE，GATEWAY
//     "productKey": "a17hN4W4777",
//     "statusLast": 3,
//     "deviceName": "testDeviceName1",
//     "iotId": "vvssa4DEzVglIGxDl777000000",
//     "namespace": "TmallGenie",
//     "tenantId": "19A31790C888469BAFE4C384FFD60777",
//     "thingType": "DEVICE",
//     "categoryId": 487,
//     "status": {
//         "time": 1604985312231,
//         "value": 1
//     },
//
//     "tenantInstanceId": "iotx-oxssharez200"
// }

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:0];
    NSString *dataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSDictionary *map = @{
        @"meshAddress":mIotId,
        @"opcode":@"/app/down/thing/status",
        @"params":dataStr,
    };
    [mRnModule sendEventWithName:kNotificationVendorResponse body:map];
}

- (void)onEventHappen:(NSString *)iotId params:(NSDictionary *)data {
    NSLog(@"DeviceObserver onEventHappen iotId->%@ data->%@", iotId, data);

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:0];
    NSString *dataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSDictionary *map = @{
        @"meshAddress":mIotId,
        @"opcode":@"/app/down/_thing/event/notify",
        @"params":dataStr,
    };
    [mRnModule sendEventWithName:kNotificationVendorResponse body:map];
}

- (void)onLocalConnectionStateChange:(IMSLocalConnectionState)state {
    NSLog(@"DeviceObserver onLocalConnectionStateChange iotId->%@ state->%ld", mIotId, (long)state);
// // 本地在线离线变更的通知
// state->2 // 1 表示本地在线，2 表示本地离线，3 表示本地连接中

    NSDictionary *data = @{
        @"localConnectionState": [NSNumber numberWithInteger:state],
    };

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:0];
    NSString *dataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSDictionary *map = @{
        @"meshAddress":mIotId,
        @"opcode":@"BoneThingLocalConnectionChange",
        @"params":dataStr,
    };
    [mRnModule sendEventWithName:kNotificationVendorResponse body:map];
}

- (void)onDeviceUnbind:(NSString *)iotId params:(NSDictionary *)data {
    NSLog(@"DeviceObserver onDeviceUnbind iotId->%@ data->%@", iotId, data);
// // after '/living/device/reset', or
// // after breezeSubDevLogin() in FYSDK.java against a reset device while it's data still in panelDevices
// iotId->vvssa4DEzVglIGxDl777000000
// data->{
//     "identifier": "awss.BindNotify",
//     "value": {
//         "iotId": "vvssa4DEzVglIGxDl777000000",
//         "identityId": "5022op8fb006f88b482b3f54d8541e0c1dfd0254",
//         "owned": 1,
//         "productKey": "a17hN4W4777",
//         "deviceName": "testDeviceName1",
//         "operation": "Unbind"
//     }
// }

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:0];
    NSString *dataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSDictionary *map = @{
        @"meshAddress":mIotId,
        @"opcode":@"/app/down/_thing/event/notify",
        @"params":dataStr,
    };
    [mRnModule sendEventWithName:kNotificationVendorResponse body:map];
}
- (void)onDeviceWifiStatus:(NSString *)iotId params:(NSDictionary*)data {
    NSLog(@"DeviceObserver onDeviceWifiStatus iotId->%@ data->%@", iotId, data);
}
@end
