//
//  SceneDelegate.m
//  WaboIOSSDKOCDemo
//
//  Created by Bepic on 2022/11/28.
//

#import "SceneDelegate.h"
#import <objc/runtime.h>
#import <WaboTestUI/WaboTestUI.h>
#import <WaboBase/WaboBase-Swift.h>
#import <WaboSDK/WaboSDK-Swift.h>

@interface SceneDelegate()<WaboSDKDelegate, WaboSDKAppopenAdDelegate, WaboSDKRewardAdDelegate, WaboSDKInterstitialAdDelegate, WaboSDKBannerAdDelegate, WaboSDKNativeAdDelegate>
@property (retain) NSString * transferCode;
@property (retain) UIView * manualNativeAdView;
@end

@implementation SceneDelegate


- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
}

- (void)sceneDidDisconnect:(UIScene *)scene {
    // Called as the scene is being released by the system.
    // This occurs shortly after the scene enters the background, or when its session is discarded.
    // Release any resources associated with this scene that can be re-created the next time the scene connects.
    // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}

- (NSString * _Nullable) dictionaryToJsonString:(id _Nullable) obj {
    if (nil == obj) return nil;
    NSError *err;
    NSData * jsonData = [NSJSONSerialization dataWithJSONObject:obj options:NSJSONWritingPrettyPrinted error:&err];
    if (err) return nil;
    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}

- (NSDictionary * _Nullable) jsonStringToDictionary:(NSString * _Nullable) jsonString {
    if (nil == jsonString) return nil;
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSError *err;
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                        options:NSJSONReadingMutableContainers
                                                          error:&err];
    if (err) {
        NSLog(@"Error json:%@", err);
        return nil;
    }
    return dict;
}

- (void)sceneDidBecomeActive:(UIScene *)scene {
    // Called when the scene has moved from an inactive state to an active state.
    // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    // [[WaboSDK sharedInstance] setDebugGeography:WaboUMPDebugGeographyEEA];
#pragma mark - Attribute
    [[WaboTestUI sharedInstance] setBannerCustomModeDelegate:^{
        [[WaboTestUI sharedInstance] addLog:@"Enable Banner Custom Mode" lineNumber:1];
        [[WaboSDK sharedInstance] setBannerCustomMode:YES];
    }];
    [[WaboTestUI sharedInstance] setInitSdkDelegate:^{
        [[WaboTestUI sharedInstance] addLog:@"start init wabosdk..." lineNumber:1];
        [[WaboSDK sharedInstance] setWaboAppopenAdDelegate:self];
        [[WaboSDK sharedInstance] setWaboRewardAdDelegate:self];
        [[WaboSDK sharedInstance] setWaboInterstitialAdDelegate:self];
        [[WaboSDK sharedInstance] setWaboBannerAdDelegate:self];
        [[WaboSDK sharedInstance] setWaboTransactionStatusDelegate:^(WaboStatusCode * _Nonnull statusCode) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"transaction status code:%lu; msg:%@;", [statusCode getCode], [statusCode getMsg]] lineNumber:2];
        }];
        [[WaboSDK sharedInstance] sdkInit:self];
    }];
    [[WaboTestUI sharedInstance] setShowAttributeInfoDelegate:^{
        WaboAttrInfo * _Nullable attrInfo = [[WaboSDK sharedInstance] getAttrInfo];
        if (nil == attrInfo) {
            [[WaboTestUI sharedInstance] addLog:@"attr info is null" lineNumber:1];
        } else {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"attrInfo attrid:%@; network:%@; campaign:%@; adgroup:%@; creative:%@;", attrInfo.attrid, attrInfo.network, attrInfo.campaign, attrInfo.adgroup, attrInfo.creative] lineNumber:3];
        }
    }];
#pragma mark - UMP
    [[WaboTestUI sharedInstance] setGetUMPParametersDelegate:^{
        NSString * _Nonnull jsonString = [[WaboSDK sharedInstance] getUMPParameters];
        NSLog(@"UMPParameters -> %@", jsonString);
        NSData * _Nullable jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
        NSError * err;
        NSDictionary * dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
        if (err) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%@", [err domain]] lineNumber:1];
            return;
        }
        
        BOOL isEuropean = [dict[@"isEuropean"] boolValue];
        BOOL isGDPR = [dict[@"isGDPR"] boolValue];
        BOOL canRequestAds = [dict[@"canRequestAds"] boolValue];
        BOOL canShowPersonalizedGoogleAds = [dict[@"canShowPersonalizedGoogleAds"] boolValue];
        BOOL canShowGoogleAds = [dict[@"canShowGoogleAds"] boolValue];
        BOOL canShowLimitedGoogleAds = [dict[@"canShowLimitedGoogleAds"] boolValue];

        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"isEuropean: %@\nisGDPR:%@\ncanRequestAds:%@\ncanShowPersonalizedGoogleAds:%@\ncanShowGoogleAds:%@\ncanShowLimitedGoogleAds:%@",
                                             isEuropean?@"true":@"false",
                                             isGDPR?@"true":@"false",
                                             canRequestAds?@"true":@"false",
                                             canShowPersonalizedGoogleAds?@"true":@"false",
                                             canShowGoogleAds?@"true":@"false",
                                             canShowLimitedGoogleAds?@"true":@"false"]
                                 lineNumber:6];
    }];
    [[WaboTestUI sharedInstance] setIsPrivacyOptionsRequiredDelegate:^{
        BOOL isRequired = [[WaboSDK sharedInstance] isPrivacyOptionsRequired];
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"PrivacyOptions: %@", isRequired?@"true":@"false"] lineNumber:1];
        
    }];
    [[WaboTestUI sharedInstance] setShowPrivacyOptionsFormDelegate:^{
        [[WaboSDK sharedInstance] showPrivacyOptionsForm:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"ShowPrivacyOptionsForm code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }];
#pragma mark - Upload Log
    [[WaboTestUI sharedInstance] setOnUploadLog:^{
        [[WaboTestUI sharedInstance] addLog:@"upload log - call" lineNumber:1];
        [[WaboSDK sharedInstance] onLog:@"test_log_name" paramMap:@{
            @"test_key_1":@"test_value_1"
        }];
    }];
    [[WaboTestUI sharedInstance] setOnUploadCustomEventDelegate:^{
        [[WaboTestUI sharedInstance] addLog:@"upload custom event - call" lineNumber:1];
        WaboCustomEvent * customEvent = [[WaboCustomEvent alloc] init];
        customEvent.eventName = @"test_event_name";
        customEvent.eventTag = @"test_event_tag";
        customEvent.logs = @{
            @"test_key_logs":@"test_value_logs"
        };
        customEvent.partnerParameter = @{
            @"test_key_partner":@"test_value_partner"
        };
        customEvent.callbackParameter = @{
            @"test_key_callback":@"test_value_callback"
        };
        customEvent.revenue = @{
            @"test_key_revenue":@(0.1)
        };
        customEvent.callbackId = @"test_callbackId";
        customEvent.orderId = @"test_orderId";
        customEvent.productId = @"test_productId";
        customEvent.purchaseToken = @"test_purchaseToken";
        [[WaboSDK sharedInstance] onUploadCustomEvent:customEvent];
    }];
    [[WaboTestUI sharedInstance] setOnCustomEventPurchaseDelegate:^{
        [[WaboTestUI sharedInstance] addLog:@"custom event purchase - call" lineNumber:1];
        WaboCustomEvent * customEvent = [[WaboCustomEvent alloc] init];
        customEvent.eventName = @"9qq8a4";
        customEvent.eventTag = @"adjust";
        customEvent.revenue = @{
            @"USD":@(0.1)
        };
        [[WaboSDK sharedInstance] onUploadCustomEvent:customEvent];
    }];
#pragma mark - Advertising
    [[WaboTestUI sharedInstance] setIsRewardedAdReadyDelegate:^{
        if ([[WaboSDK sharedInstance] isRewardedAdReady:nil]) {
            [[WaboTestUI sharedInstance] addLog:@"Rewarded is ready" lineNumber:1];
        } else {
            [[WaboTestUI sharedInstance] addLog:@"Rewarded is not ready" lineNumber:1];
        }
    }];
    [[WaboTestUI sharedInstance] setShowRewardedAdDelegate:^{
        if ([[WaboSDK sharedInstance] isRewardedAdReady:nil]) {
            [[WaboSDK sharedInstance] showRewardedAd:nil];
        }
    }];
    [[WaboTestUI sharedInstance] setIsInterstitialAdReadyDelegate:^{
        if ([[WaboSDK sharedInstance] isInterstitialAdReady:@""]) {
            [[WaboTestUI sharedInstance] addLog:@"Interstitial is ready" lineNumber:1];
        } else {
            [[WaboTestUI sharedInstance] addLog:@"Interstitial is not ready" lineNumber:1];
        }
    }];
    [[WaboTestUI sharedInstance] setShowInterstitialAdDelegate:^{
        if ([[WaboSDK sharedInstance] isInterstitialAdReady:nil]) {
            [[WaboSDK sharedInstance] showInterstitialAd:nil];
        }
    }];
    [[WaboTestUI sharedInstance] setIsBannerAdReadyDelegate:^{
        if ([[WaboSDK sharedInstance] isBannerAdReady]) {
            [[WaboTestUI sharedInstance] addLog:@"Banner is ready" lineNumber:1];
        } else {
            [[WaboTestUI sharedInstance] addLog:@"Banner is not ready" lineNumber:1];
        }
    }];
    [[WaboTestUI sharedInstance] setShowBannerAdDelegate:^{
        if ([[WaboSDK sharedInstance] isBannerAdReady]) {
            [[WaboSDK sharedInstance] showBannerAd];
        }
    }];
    [[WaboTestUI sharedInstance] setHideBannerAdDelegate:^{
        [[WaboSDK sharedInstance] hideBannerAd];
    }];
    [[WaboTestUI sharedInstance] setShowBannerAdTopDelegate:^{
        if ([[WaboSDK sharedInstance] isBannerAdReady]) {
            [[WaboSDK sharedInstance] showBannerAdTop];
        }
    }];
    [[WaboTestUI sharedInstance] setShowBannerAdBottomDelegate:^{
        if ([[WaboSDK sharedInstance] isBannerAdReady]) {
            [[WaboSDK sharedInstance] showBannerAdBottom];
        }
    }];
    [[WaboTestUI sharedInstance] setShowBannerAdTopOfSafeDelegate:^{
        if ([[WaboSDK sharedInstance] isBannerAdReady]) {
            [[WaboSDK sharedInstance] showBannerAdTopOfSafe];
        }
    }];
    [[WaboTestUI sharedInstance] setShowBannerAdBottomOfSafeDelegate:^{
        if ([[WaboSDK sharedInstance] isBannerAdReady]) {
            [[WaboSDK sharedInstance] showBannerAdBottomOfSafe];
        }
    }];
    [[WaboTestUI sharedInstance] setShowBannerAdWithPositionDelegate:^{
        if ([[WaboSDK sharedInstance] isBannerAdReady]) {
            [[WaboSDK sharedInstance] showBannerAdWithPosition:0.0F :128.0F];
        }
    }];
    [[WaboTestUI sharedInstance] setGetBannerSizeDelegate:^{
        CGSize size = [[WaboSDK sharedInstance] getBannerSize];
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Banner size (%f, %f)", size.width, size.height] lineNumber:1];
    }];
    [[WaboTestUI sharedInstance] setCreateBannerViewDelegate:^{
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Create Banner -"] lineNumber:1];
        CGSize size = [[WaboSDK sharedInstance] getBannerSize];
        UIView * bannerAd = [[WaboSDK sharedInstance] createBanner];
        UIView * parentView = [[UIView alloc] init];
        parentView.frame = CGRectMake(0, UIScreen.mainScreen.bounds.size.height - size.height, size.width, size.height + UIApplication.sharedApplication.keyWindow.safeAreaInsets.bottom);
        bannerAd.frame = CGRectMake(0, 0, size.width, size.height);
        [parentView addSubview:bannerAd];
        [UIApplication.sharedApplication.keyWindow addSubview:parentView];
    }];
    [[WaboTestUI sharedInstance] setDestroyBannerViewDelegate:^{
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Destroy Banner -"] lineNumber:1];
        [[WaboSDK sharedInstance] destroyBanner];
    }];
    [[WaboTestUI sharedInstance] setShowAppopenAdWithTimeoutDelegate:^{
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Show Appopen Ad - Call"] lineNumber:1];
        [[WaboSDK sharedInstance] showAppopenAdWithTimeout:5.0F];
    }];
    [[WaboTestUI sharedInstance] setShowSmallNativeAdDelegate:^{
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Show Small Native Ad - Call"] lineNumber:1];
        [[WaboSDK sharedInstance] showSmallNativeAd:self];
    }];
    [[WaboTestUI sharedInstance] setShowMediumNativeAdDelegate:^{
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Show Medium Native Ad - Call"] lineNumber:1];
        [[WaboSDK sharedInstance] showMediumNativeAd:self];
    }];
    [[WaboTestUI sharedInstance] setShowManualNativeAdDelegate:^{
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Show Manual Native Ad - Call"] lineNumber:1];
        WaboNativeAdBinder *nativeAdBinder = [[WaboNativeAdBinder alloc] init];
        [nativeAdBinder xibName:@"Wabo_Native_Ad_Manual"];
        [nativeAdBinder iconImageViewTag:1];
        [nativeAdBinder titleLabelTag:3];
        [nativeAdBinder advertiserLabelTag:4];
        [nativeAdBinder bodyLabelTag:5];
        [nativeAdBinder callToActionButtonTag:6];
        [nativeAdBinder starRatingContentViewTag:7];
        [nativeAdBinder mediaContentViewTag:8];
        [nativeAdBinder optionsContentViewTag:9];
        [[WaboSDK sharedInstance] showManualNativeAdWithBinder:nativeAdBinder delegate:self];
    }];
    [[WaboTestUI sharedInstance] setDestroyNativeAdViewDelegate:^{
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Destroy Native Ad - Call"] lineNumber:1];
        if (Nil != self.manualNativeAdView) {
            [[WaboSDK sharedInstance] destroyNativeAdView:self.manualNativeAdView];
        }
    }];
#pragma mark - Login
    [[WaboTestUI sharedInstance] setOnAutoLoginDelegate:^{
        [[WaboTestUI sharedInstance] addLog:@"start auto login" lineNumber:1];
        [[WaboSDK sharedInstance] autoLoginAsync:false success:^(WaboAutoLoginResult * _Nonnull result) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"autoLoginAsync success gameId: %@; gameAccountId: %lld; saveGameId: %@; saveId: %lld; loginType: %@; isNew: %@;", result.gameId, result.gameAccountId, result.saveGameId, result.saveId, result.loginType, result.isNew ? @"true" : @"false"] lineNumber:4];
            [[WaboSDK sharedInstance] uploadRoleLogin:@"s1" serverName:@"zhangjiajie" roleId:@"007" roleName:@"zhangsan"];
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"autoLoginAsync failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:3];
        }];
    }];
    [[WaboTestUI sharedInstance] setOnCheckLoginDelegate:^{
        [[WaboTestUI sharedInstance] addLog:@"start check login" lineNumber:1];
        [[WaboSDK sharedInstance] checkLoginAsync:^(WaboCheckLoginResult * _Nonnull result) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"checkLoginAsync success gameId: %@; gameAccountId: %lld; saveGameId: %@; saveId: %lld; loginType: %@;", result.gameId, result.gameAccountId, result.saveGameId, result.saveId, result.loginType] lineNumber:4];
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"checkLoginAsync failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }];
    [[WaboTestUI sharedInstance] setOnLoginDelegate:^{
        [[WaboTestUI sharedInstance] addLog:@"start login" lineNumber:1];
        NSArray * loginTypes = [[WaboSDK sharedInstance] getLoginTypes];
        if (0 == loginTypes.count) { [[WaboTestUI sharedInstance] addLog:@"no login type" lineNumber:1]; return; }
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"loginTypes: %@", loginTypes] lineNumber:loginTypes.count + 2];
        [[WaboTestUI sharedInstance] addSelectPanel:loginTypes :^(id _Nonnull loginType) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"login select %@", loginType] lineNumber:1];
            [[WaboSDK sharedInstance] loginWithTypeAsync:[NSString stringWithFormat:@"%@", loginType] success:^(WaboLoginResult * _Nonnull result) {
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"loginWithType success gameAccountId: %lld; saveGameId: %@; saveId: %lld; loginType: %@; isNew: %@; sessionToken: %@;", result.gameAccountId, result.saveGameId, result.saveId, result.loginType, result.isNew ? @"true" : @"false", result.sessionToken] lineNumber:4];
            } failed:^(WaboStatusCode * _Nonnull status) {
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"loginWithType failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
            }];
        }];
    }];
    [[WaboTestUI sharedInstance] setOnBindUserDelegate:^{
        NSArray * loginTypes = [[WaboSDK sharedInstance] getLoginTypes];
        if (0 == loginTypes.count) { [[WaboTestUI sharedInstance] addLog:@"no login type" lineNumber:1]; return; }
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"loginTypes: %@", loginTypes] lineNumber:loginTypes.count + 2];
        [[WaboTestUI sharedInstance] addSelectPanel:loginTypes :^(id _Nonnull loginType) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"bind user select %@", loginType] lineNumber:1];
            [[WaboSDK sharedInstance] bindWithTypeAsync:[NSString stringWithFormat:@"%@", loginType]  success:^(WaboUserInfoResult * _Nonnull result) {
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"bind user success gameId:%@; gameAccountId:%lld; loginInfos:%lu", result.gameId, result.gameAccountId, (unsigned long)result.loginInfo.count] lineNumber:3];
                for (long i = 0, len = result.loginInfo.count; i < len; i++) {
                    WaboLoginInfo * waboLoginInfo = result.loginInfo[i];
                    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%lu - %@ - %@ - %@", i, waboLoginInfo.platform, waboLoginInfo.hasLinked ? @"true" : @"false", waboLoginInfo.uniqeId] lineNumber:2];
                }
            } failed:^(WaboStatusCode * _Nonnull status) {
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"bind user failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:4];
            }];
        }];
    }];
    [[WaboTestUI sharedInstance] setOnUnBindUserDelegate:^{
        NSArray * loginTypes = [[WaboSDK sharedInstance] getLoginTypes];
        if (0 == loginTypes.count) { [[WaboTestUI sharedInstance] addLog:@"no login type" lineNumber:1]; return; }
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"loginTypes: %@", loginTypes] lineNumber:loginTypes.count + 2];
        [[WaboTestUI sharedInstance] addSelectPanel:loginTypes :^(id _Nonnull loginType) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"un bind user select %@", loginType] lineNumber:1];
            [[WaboSDK sharedInstance] unbindWithTypeAsync:[NSString stringWithFormat:@"%@", loginType]  success:^(WaboUserInfoResult * _Nonnull result) {
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"un bind user success gameId:%@; gameAccountId:%lld; loginInfos:%lu", result.gameId, result.gameAccountId, (unsigned long)result.loginInfo.count] lineNumber:3];
                for (long i = 0, len = result.loginInfo.count; i < len; i++) {
                    WaboLoginInfo * waboLoginInfo = result.loginInfo[i];
                    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%lu - %@ - %@ - %@", i, waboLoginInfo.platform, waboLoginInfo.hasLinked ? @"true" : @"false", waboLoginInfo.uniqeId] lineNumber:2];
                }
            } failed:^(WaboStatusCode * _Nonnull status) {
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"un bind user failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:3];
            }];
        }];
    }];
    [[WaboTestUI sharedInstance] setGetUserInfoDelegate:^{
        [[WaboSDK sharedInstance] getUserInfoAsync:^(WaboUserInfoResult * _Nonnull result) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"get user info gameId:%@; gameAccountId:%lld; saveGameId:%@; saveId:%lld; loginInfos:%lu", result.gameId, result.gameAccountId, result.saveGameId, result.saveId, (unsigned long)result.loginInfo.count] lineNumber:3];
            for (long i = 0, len = result.loginInfo.count; i < len; i++) {
                WaboLoginInfo * waboLoginInfo = result.loginInfo[i];
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%lu - %@ - %@ - %@", i, waboLoginInfo.platform, waboLoginInfo.hasLinked ? @"true" : @"false", waboLoginInfo.uniqeId] lineNumber:2];
            }
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"get user info failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }];
    [[WaboTestUI sharedInstance] setOnLogoutDelegate:^{
        [[WaboSDK sharedInstance] logout];
        [[WaboTestUI sharedInstance] addLog:@"logout success" lineNumber:1];
    }];
    [[WaboTestUI sharedInstance] setOnSignOutDelegate:^{
        [[WaboSDK sharedInstance] signOut:^(WaboSignOutResult * _Nonnull result) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"sign out success code: %ld; msg: %@;", result.code, result.msg] lineNumber:2];
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"sign out failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }];
    [[WaboTestUI sharedInstance] setGetBindTransferCodeDelegate:^{
        [[WaboSDK sharedInstance] getBindTransferCode:^(WaboGetBindTransferCodeResult * _Nullable result) {
            if (nil == result) {
                [[WaboTestUI sharedInstance] addLog:@"get bind transfer code no bind" lineNumber:1];
            } else {
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"get bind transfer code gameId:%@; gameAccountId:%lld;", result.gameId, result.gameAccountId] lineNumber:2];
            }
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"get bind transfer code failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }];
    [[WaboTestUI sharedInstance] setGenerateTransferCodeDelegate:^{
        [[WaboSDK sharedInstance] generateTransferCode:^(WaboGenerateTransferCodeResult * _Nonnull result) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"generate transfer code transferCode:%@;", result.transferCode] lineNumber:4];
            self.transferCode = result.transferCode;
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"generate transfer code failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }];
    [[WaboTestUI sharedInstance] setBindTransferCodeDelegate:^{
        if (nil == self.transferCode) {
            [[WaboTestUI sharedInstance] addLog:@"no find transfer code" lineNumber:1];
            return;
        }
        [[WaboSDK sharedInstance] bindTransferCode:self.transferCode success:^(WaboBindTransferCodeResult * _Nonnull result) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"bind transfer code gameId:%@; gameAccountId:%lld;", result.gameId, result.gameAccountId] lineNumber:2];
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"bind transfer code failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }];
#pragma mark - Purchase
    [[WaboTestUI sharedInstance] setGetShopItemsDelegate:^{
        NSArray<WaboShopItem *> * _Nullable shopItems = [[WaboSDK sharedInstance] getShopItems];
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"ShopItems - Sync - %ld", shopItems.count] lineNumber:1];
        if (nil != shopItems) {
            for (long i = 0, len = shopItems.count; i < len; i++) {
                WaboShopItem * shopItem = shopItems[i];
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%ld:%@ - %@ - %@ - %@ - %ld - %@ - %@ - %@ - %d - %d - %d", i, shopItem.itemId, shopItem.itemType, shopItem.formattedPrice, shopItem.currency, shopItem.type, shopItem.appleStoreId, shopItem.usdPrice, shopItem.price, shopItem.isConsume, shopItem.isOneTime, shopItem.isSubscription] lineNumber:2];
            }
        } else {
            [[WaboTestUI sharedInstance] addLog:@"no shop item" lineNumber:1];
        }
    }];
    [[WaboTestUI sharedInstance] setGetShopItemsAsyncDelegate:^{
        [[WaboSDK sharedInstance] getShopItemsAsyncWithSuccecc:^(NSArray<WaboShopItem *> * _Nonnull shopItems) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"ShopItems - Async - %ld", shopItems.count] lineNumber:1];
            if (nil != shopItems) {
                for (long i = 0, len = shopItems.count; i < len; i++) {
                    WaboShopItem * shopItem = shopItems[i];
                    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%ld:%@ - %@ - %@ - %@ - %ld - %@ - %@ - %@ - %d - %d - %d", i, shopItem.itemId, shopItem.itemType, shopItem.formattedPrice, shopItem.currency, shopItem.type, shopItem.appleStoreId, shopItem.usdPrice, shopItem.price, shopItem.isConsume, shopItem.isOneTime, shopItem.isSubscription] lineNumber:2];
                }
            } else {
                [[WaboTestUI sharedInstance] addLog:@"no shop item" lineNumber:1];
            }
        } failed:^(WaboStatusCode * _Nonnull statusCode) {
            [[WaboTestUI sharedInstance] addLog:[statusCode toJson] lineNumber:1];
        }];
    }];
    [[WaboTestUI sharedInstance] setOnPaymentDelegate:^{
        NSArray<WaboShopItem *> * _Nullable shopItems = [[WaboSDK sharedInstance] getShopItems];
        if (nil != shopItems) {
            if (0 == shopItems.count) { [[WaboTestUI sharedInstance] addLog:@"no shop item" lineNumber:1]; return; }
            NSMutableArray<NSString *> * shopItemArray = [NSMutableArray arrayWithCapacity:shopItems.count];
            for (long i = 0, len = shopItems.count; i < len; i++) {
                WaboShopItem * shopItem = shopItems[i];
                [shopItemArray addObject:shopItem.itemId];
            }
            [[WaboTestUI sharedInstance] addSelectPanel:shopItemArray :^(id _Nonnull itemId) {
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"payment select %@", itemId] lineNumber:1];
                NSDictionary<NSString *,NSString *> * extraInfo = @{@"key1":@"value1"};
                [[WaboSDK sharedInstance] startPaymentWithEnvIdAndExtraInfo:[NSString stringWithFormat:@"%@", itemId] cpOrderId:nil envId:nil extraInfo:extraInfo success:^(WaboPaymentResult * _Nonnull result) {
                    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"payment success itemId: %@; type:%ld; gameOrderId:%lld;", result.itemId, (long)result.type, result.gameOrderId] lineNumber:2];
                    if (result.isConsume) {
                        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%@ as consume, need to be consumed", result.itemId] lineNumber:1];
                        [[WaboSDK sharedInstance] onConsumeItem:result.gameOrderId success:^(int64_t gameOrderId) {
                            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%@ consume success", result.itemId] lineNumber:1];
                        } failed:^(WaboStatusCode * _Nonnull status) {
                            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%@ consume failed code: %ld; msg: %@;", result.itemId, (long)[status getCode], [status getMsg]] lineNumber:2];
                        }];
                    } else if (result.isOneTime) {
                        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%@ as onetime", result.itemId] lineNumber:1];
                    } else if (result.isSubscription) {
                        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%@ as subscription", result.itemId] lineNumber:1];
                    } else {
                        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%@ as unknown", result.itemId] lineNumber:1];
                    }
                } failed:^(WaboStatusCode * _Nonnull status) {
                    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"payment failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
                }];
            }];
        }
    }];
    [[WaboTestUI sharedInstance] setOnQueryOneTimeItemsDelegate:^{
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"start query one time items"] lineNumber:1];
        [[WaboSDK sharedInstance] queryOneTimeItemAsync:^(NSArray<WaboOneTimeItem *> * _Nonnull oneTimeItems) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"query one time items success %ld", oneTimeItems.count] lineNumber:1];
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"query one time items failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }];
    [[WaboTestUI sharedInstance] setOnQuerySubscriptionItemsDelegate:^{
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"start query subscription items"] lineNumber:1];
        [[WaboSDK sharedInstance] querySubscriptionAsync:^(NSArray<WaboSubscriptionItem *> * _Nonnull subscriptionItems) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"query subscription items success %ld", subscriptionItems.count] lineNumber:1];
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"query subscription items failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }];
    [[WaboTestUI sharedInstance] setOnRestoreDelegate:^{
        [[WaboSDK sharedInstance] onRestoreApplePurchases];
    }];
    [[WaboTestUI sharedInstance] setOnShareDelegate:^{
        NSArray * shareTypes = [[WaboSDK sharedInstance] getShareTypes];
        if (0 == shareTypes.count) { [[WaboTestUI sharedInstance] addLog:@"no share type" lineNumber:1]; return; }
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"shareTypes: %@", shareTypes] lineNumber:shareTypes.count + 2];
        [[WaboTestUI sharedInstance] addSelectPanel:shareTypes :^(id _Nonnull shareType) {
            NSArray * shareMethods = @[@"link", @"photo"];
            [[WaboTestUI sharedInstance] addSelectPanel:shareMethods :^(id _Nonnull shareMethod) {
                [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"share %@ select %@;", shareType, shareMethod] lineNumber:1];
                if ([@"link" isEqualToString:shareMethod]) {
                    NSString * url = @"https://www.baidu.com";
                    [[WaboSDK sharedInstance] shareLink:shareType url:url success:^(NSString * _Nonnull shareType) {
                        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"share link success %@;", shareType] lineNumber:1];
                    } failed:^(WaboStatusCode * _Nonnull status) {
                        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"share link failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
                    }];
                } else if ([@"photo" isEqualToString:shareMethod]) {                    
                    NSString * imageString = @"iVBORw0KGgoAAAANSUhEUgAAACAAAAARCAIAAAAzPjmrAAAE+UlEQVQ4ESWVyW4dxxWG69TcM+9AUaJImYyswaOMLALbCWDAq+wC5HXyDHmPrLMykG1sIEACBPEg2JRE2qJIXvFOfW9PNaduAjQK6Oq/vjrndP2nAP/+z4HgQAEwA4xBUg+IUkoo1RgQIx4HRAAIQTsZjmOUIUJ3ryQgSlBchYECpjiqMI846nmUE08iChiNQ8D/R5D4NeI8+x8OdvMoQhmB3XychN0GsFsXeQ9SlHCYabAhYgBHTQCB7ZiFioSRII21NHBMGP7s/i7Of9yCiyoSZWAxxHgjBlEXcTHGmGWM1ROEAEnqDqT904f5aRG+nqGYikbo7zdD06vRppb1KnN6moZ3DzgNbJc1Je6TA3MyTb9b2xvFO48UQaWEbXDWAw6xbISD84jk2H02Rs+qQQR70i3ucfKHnBqnGg2yby9mmxcv32rnGnBrCO1NjI1ii8PrWj3Lw+/u0y+PyWLQrcMak++3sHDhgbQnE/lj4xJC3rT9Hw/Rs2yguk0yIXAYFOoB1z2qm77ZbE/L8PlvDw8rooyardS676mQWMqwJPlfW/qX5zBKXMqhYLQS8Lw1H5b4031XlvZc47POCy4uzfBBkpfTPco4j3+Vy0WPzmOFpP3NgX0yCVlw7aK+fNvsjflJOaIP0+1RTuayMkAes9ABfmH5ZSBUo7sVkIx8a7BdkmvPPrmD3i9pD/lPEPQAd0BMOahWT7F/RDqsmim2Zk1gr5icnKbHsOnsXkYo+8/fVok8ffqo2L9TCJZNy18hjwlJMBxwGDM/TRBieOaTeILL+CAiwrDPoErZ2/nix/Pl2Zutauv7KSokrUbZ/akvM2U8TpKkKvdoCV3f+ctvf7Dh30lZVodHhWQfPT4aF2nioGTs8X7l8vI9xjHPdg4xHdV+lMgklX1x9+zW/muxEJ63EKYYHzpZ0fH+dDKJrDxHJB7yfGygenmz5kgXtru4eQlGLy9njz5+LKf7GPmLrk5H+Eqh9+75Xx9P8ny0dUVDRW3gm1/mX71W5d39CqwISqbEkPSy9/Vci0wlCiQBmozL2cJjJhBhDcGWIU7oL7eD/e5icmRvxXT9shtYtxb50ZU//bmbpIyJaGJ4fbm8brUBWnFhHTKEDVky5FKUBQhZW/TD1dZhT1+smgAozal2WBESLS7lno4+wHR+czOI5mKgJK9cgX5G8OqqNiF6EawzGYap4AH5VfBVkUou5zjrBjgL7qEPm1Y9n8ckDe2GGiGidVDWC8aPHxweVJNVE42JTAgHZNvpuV0HiSprsk7em+l8o0zcwwDCCeIytixiDKexB2kjWXq9NP88f52AR8F165pKzhjP6o1VKtCMc5k610tJ39RGG3y1CpXIKrEYttelhyfV9TIdn6/yRJSzFnedNTY2SdEHOwRHB0v6ZVNv7e1cDYuC9yVxtGL5MMS6SyuDlFm7VZ4h50wqswFcr6kz3KBy1tSZ6ms135+8OCIV4PF0OlpZphTdqJznKA1u/uqMbBdFt3G6CX0N2ASiKHLrYIPpTZYkMngJWZrkjSV790Z09UbwV6fj5eHY3myRdjUjam1xs2mRu74zQmWAVouHSTQG+MZrvXFEQRFbIwneOhdCMPDoi6eEyvXWImDBoXdPiuN3Ro7TRbdmtkvQbZ77zsVLorRqKblqFTQK8xynUkVM7L2CGeIVQrFCLtY5NncE3mi0aajW9L/yrp7wvsDabwAAAABJRU5ErkJggg==";
                    NSData * imageData = [[NSData alloc] initWithBase64EncodedString:imageString options:NSDataBase64DecodingIgnoreUnknownCharacters];
                    UIImage * image = [UIImage imageWithData: imageData];
                    [[WaboSDK sharedInstance] sharePhoto:shareType image:image success:^(NSString * _Nonnull shareType) {
                        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"share photo success %@;", shareType] lineNumber:1];
                    } failed:^(WaboStatusCode * _Nonnull status) {
                        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"share photo failed code: %ld; msg: %@;", (long)[status getCode], [status getMsg]] lineNumber:2];
                    }];
                }
            }];
        }];
    }];
    
    [[WaboTestUI sharedInstance] setOnBuglyDelegate:^{
        NSArray * array = @[];
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"test bugly %@;", array[0]] lineNumber:1];
    }];
    [[WaboTestUI sharedInstance] onInit];
}

- (void)sceneWillResignActive:(UIScene *)scene {
    // Called when the scene will move from an active state to an inactive state.
    // This may occur due to temporary interruptions (ex. an incoming phone call).
}


- (void)sceneWillEnterForeground:(UIScene *)scene {
    // Called as the scene transitions from the background to the foreground.
    // Use this method to undo the changes made on entering the background.
}


- (void)sceneDidEnterBackground:(UIScene *)scene {
    // Called as the scene transitions from the foreground to the background.
    // Use this method to save data, release shared resources, and store enough scene-specific state information
    // to restore the scene back to its current state.
}


- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts  API_AVAILABLE(ios(13.0)){
    [[WaboSDK sharedInstance] scene:scene openURLContexts:URLContexts];
}

#pragma mark - Delegate Wabo SDK
- (void)onWaboSdkInitResult:(WaboStatusCode * _Nonnull)statusCode {
    if (statusCode == WaboStatusCode.Success) {
        WaboAttrInfo * _Nullable attrInfo = [[WaboSDK sharedInstance] getAttrInfo];
        [[WaboSDK sharedInstance] onUploadIntoGame:@"s1" server_name:@"server1" role_id:@"n1" role_name:@"name1"];
        if (nil == attrInfo) {
            [[WaboTestUI sharedInstance] addLog:@"init wabosdk success attrInfo null" lineNumber:1];
        } else {
            [[WaboTestUI sharedInstance] addLog:@"init wabosdk success" lineNumber:1];
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"attrid:%@; network:%@; campaign:%@; adgroup:%@; creative:%@;", attrInfo.attrid, attrInfo.network, attrInfo.campaign, attrInfo.adgroup, attrInfo.creative] lineNumber:3];
        }
        
        NSString * _Nonnull jsonString = [[WaboSDK sharedInstance] getUMPParameters];
        BOOL isRequired = [[WaboSDK sharedInstance] isPrivacyOptionsRequired];
        NSData * _Nullable jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
        NSError * err;
        NSDictionary * dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
        if (err) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"ump error: %@", [err domain]] lineNumber:1];
            return;
        }
        
        BOOL isGDPR = dict[@"isGDPR"];
        if (isGDPR && isRequired) {
            [[WaboTestUI sharedInstance] addButton:@"Show Privacy Options Form"];
        }
                
        BOOL isEuropean = [dict[@"isEuropean"] boolValue];
        // BOOL isGDPR = [dict[@"isGDPR"] boolValue];
        BOOL canRequestAds = [dict[@"canRequestAds"] boolValue];
        BOOL canShowPersonalizedGoogleAds = [dict[@"canShowPersonalizedGoogleAds"] boolValue];
        BOOL canShowGoogleAds = [dict[@"canShowGoogleAds"] boolValue];
        BOOL canShowLimitedGoogleAds = [dict[@"canShowLimitedGoogleAds"] boolValue];

        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"isEuropean: %@\nisGDPR:%@\ncanRequestAds:%@\ncanShowPersonalizedGoogleAds:%@\ncanShowGoogleAds:%@\ncanShowLimitedGoogleAds:%@",
                                             isEuropean?@"true":@"false",
                                             isGDPR?@"true":@"false",
                                             canRequestAds?@"true":@"false",
                                             canShowPersonalizedGoogleAds?@"true":@"false",
                                             canShowGoogleAds?@"true":@"false",
                                             canShowLimitedGoogleAds?@"true":@"false"]
                                 lineNumber:6];
        
    } else {
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"init wabosdk failed code:%ld; errorMsg:%@;", [statusCode getCode], [statusCode getMsg]] lineNumber:2];
    }
}

- (void)onWaboSdkAttrChanged:(WaboAttrInfo * _Nullable)attrInfo {
    if (nil == attrInfo) {
        [[WaboTestUI sharedInstance] addLog:@"attr_on attrInfo null" lineNumber:1];
        return;
    }
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"attr_on attrid:%@; network:%@; campaign:%@; adgroup:%@; creative:%@;", attrInfo.attrid, attrInfo.network, attrInfo.campaign, attrInfo.adgroup, attrInfo.creative] lineNumber:3];
}

- (void)onWaboSdkAdvertisingActive {
    [[WaboSDK sharedInstance] showAppopenAdWithTimeout:5.0F];
}

- (void)onWaboSdkPullUnConsumeItems:(NSArray<WaboUnConsumeItem *> *)unConsumeItems {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"find un consume item: %ld;", unConsumeItems.count] lineNumber:1];
    for (int i = 0; i < unConsumeItems.count; i++) {
        WaboUnConsumeItem * unConsumeItem = unConsumeItems[i];
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%d) gameOrderId: %lld; itemId: %@; createTime: %lld; purchaseTime: %lld; status: %ld;", i, unConsumeItem.gameOrderId, unConsumeItem.itemId, unConsumeItem.createTime, unConsumeItem.purchaseTime, unConsumeItem.status] lineNumber:3];
        [[WaboSDK sharedInstance] onConsumeItem:unConsumeItem.gameOrderId success:^(int64_t gameOrderId) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%@ consume success", unConsumeItem.itemId] lineNumber:1];
        } failed:^(WaboStatusCode * _Nonnull status) {
            [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%@ consume failed code: %ld; msg: %@;", unConsumeItem.itemId, (long)[status getCode], [status getMsg]] lineNumber:2];
        }];
    }
}

- (void)onWaboSdkPullOneTimeItems:(NSArray<WaboOneTimeItem *> *)oneTimeItems {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"find one time items: %ld;", oneTimeItems.count] lineNumber:1];
    for (int i = 0; i < oneTimeItems.count; i++) {
        WaboOneTimeItem * oneTimeItem = oneTimeItems[i];
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%d) itemId: %@; productId: %@; purchaseTime: %lld;", i, oneTimeItem.itemId, oneTimeItem.productId, oneTimeItem.purchaseTime] lineNumber:2];
    }
}

- (void)onWaboSdkPullSubscriptionItems:(NSArray<WaboSubscriptionItem *> *)subscriptionItems {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"find subscription items: %ld;", subscriptionItems.count] lineNumber:1];
    for (int i = 0; i < subscriptionItems.count; i++) {
        WaboSubscriptionItem * subscriptionItem = subscriptionItems[i];
        [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"%d) itemId: %@; productId: %@; purchaseTime: %lld;", i, subscriptionItem.itemId, subscriptionItem.productId, subscriptionItem.purchaseTime] lineNumber:2];
    }
}

#pragma mark - Delegate Wabo AppopenAd
- (void)onWaboAppopenAdDiaTimeout:(NSString * _Nonnull)adUnitId {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Appopen show timeout %@;", adUnitId] lineNumber:1];
}

- (void)onWaboAppopenAdDidDisplay:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Appopen show succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboAppopenAdDidHide:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Appopen close succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboAppopenAdDidClick:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Appopen click %@;", adUnitId] lineNumber:1];
}

- (void)onWaboAppopenAdDidFailToDisplay:(NSString * _Nonnull)adUnitId code:(NSInteger)code errMsg:(NSString * _Nonnull)errMsg {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Appopen failToDisplay %@;", adUnitId] lineNumber:1];
}

- (void)onWaboAppopenAdDidLoad:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Appopen load succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboAppopenAdDidFailToLoadAd:(NSString * _Nonnull)adUnitId errorCode:(NSInteger)errorCode errorMsg:(NSString * _Nonnull)errorMsg {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Appopen load fail %@; %ld:%@", adUnitId, (long)errorCode, errorMsg] lineNumber:3];
}
#pragma mark - Delegate Wabo RewardAd
- (void)onWaboRewardAdDidDisplay:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Reward show succe %@;", adUnitId] lineNumber:1];
}

- (void)onWaboRewardAdDidHide:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Reward close succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboRewardAdDidRewardUser:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Reward reward adUnitId:%@; revenue:%f;", adUnitId, callbackInfo.revenue] lineNumber:2];
}

- (void)onWaboRewardAdDidClick:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Reward click %@;", adUnitId] lineNumber:1];
}

- (void)onWaboRewardAdDidFailToDisplay:(NSString * _Nonnull)adUnitId code:(NSInteger)code errMsg:(NSString * _Nonnull)errMsg {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Reward failToDisplay %@;", adUnitId] lineNumber:1];
}

- (void)onWaboRewardAdDidLoad:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Reward load succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboRewardAdDidFailToLoadAd:(NSString * _Nonnull)adUnitId errorCode:(NSInteger)errorCode errorMsg:(NSString * _Nonnull)errorMsg {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Reward load fail %@; %ld:%@", adUnitId, (long)errorCode, errorMsg] lineNumber:3];
}

#pragma mark - Delegate Wabo InterstitialAd
- (void)onWaboInterstitialAdDidDisplay:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Interstitial show succe %@;", adUnitId] lineNumber:1];
}

- (void)onWaboInterstitialAdDidHide:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Interstitial close succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboInterstitialAdDidClick:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Interstitial click %@;", adUnitId] lineNumber:1];
}

- (void)onWaboInterstitialAdDidLoad:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Interstitial load succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboInterstitialAdDidFailToLoadAd:(NSString * _Nonnull)adUnitId errorCode:(NSInteger)errorCode errorMsg:(NSString * _Nonnull)errorMsg {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Interstitial load fail %@; %ld:%@", adUnitId, (long)errorCode, errorMsg] lineNumber:3];
}

#pragma mark - Delegate Wabo BannerAd
- (void)onWaboBannerAdDidDisplay:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Banner show succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboBannerAdDidHide:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Banner close succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboBannerAdDidExpand:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Banner expand %@;", adUnitId] lineNumber:1];
}

- (void)onWaboBannerAdDidClick:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Banner click %@;", adUnitId] lineNumber:1];
}

- (void)onWaboBannerAdDidLoad:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Banner load succ %@;", adUnitId] lineNumber:1];
}

- (void)onWaboBannerAdDidFailToLoadAd:(NSString * _Nonnull)adUnitId errorCode:(NSInteger)errorCode errorMsg:(NSString * _Nonnull)errorMsg {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Banner load fail %@; %ld:%@", adUnitId, (long)errorCode, errorMsg] lineNumber:3];
}

#pragma mark - Delegate Wabo NativeAd
- (void)onWaboNativeAdDidLoad:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo view:(UIView * _Nullable)view {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Native load succ %@;", adUnitId] lineNumber:1];
    if (Nil != view) {
        self.manualNativeAdView = view;
        view.frame = CGRectMake(0.0, 256.0, 256, 512.0);
        [UIApplication.sharedApplication.windows.firstObject addSubview:view];
    }
}
- (void)onWaboNativeAdDidFailToLoad:(NSString * _Nonnull)adUnitId errorCode:(NSInteger)errorCode errorMsg:(NSString * _Nonnull)errorMsg {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Native load fail %@; %ld:%@", adUnitId, (long)errorCode, errorMsg] lineNumber:3];
}
- (void)onWaboNativeAdDidClick:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Native click %@;", adUnitId] lineNumber:1];
}
- (void)onWaboNativeAdDidRevenue:(NSString * _Nonnull)adUnitId callback:(WaboAdCallbackInfo * _Nonnull)callbackInfo {
    [[WaboTestUI sharedInstance] addLog:[NSString stringWithFormat:@"Native revenue %@;", adUnitId] lineNumber:1];
}
@end
