//
//  AppDelegate.m
//  aiim
//
//  Created by gan on 2025/2/27.
//

#import "AppDelegate.h"
#import "UDManager.h"
#import <UserNotifications/UserNotifications.h>
#import <PushKit/PushKit.h>
#import "CallKit/CallKit.h"
#import <AFNetworking/AFNetworkReachabilityManager.h>
#import "UserNetApi.h"
#import "CryptoAES.h"
#import "GWebSocket.h"
#import "GDBManager.h"
#import "APPLocker.h"
#import "JSGController.h"
#import "LoginStateManager.h"

#import "FloatingWindow.h"
#import "ChatIndexController.h"
#import "ChatController.h"
#import "ChatListStore.h"
#import "ChatsStore.h"

#import "OSSManager.h"

#import <Bugly/Bugly.h>

#ifdef DEBUG
#import <DoraemonKit/DoraemonManager.h>
#endif


@import JitsiMeetSDK;

@interface AppDelegate ()<UNUserNotificationCenterDelegate,PKPushRegistryDelegate,CXProviderDelegate>
{
    BOOL _isReachable;
}
@property (nonatomic, strong) CXProvider *callProvider;
@property (nonatomic) NSUUID *uuid;
@property (nonatomic) NSDictionary *msg;
@property (strong, nonatomic) NSString *bgMark;

@property (nonatomic) BOOL isTokenCleared;

@property (strong, nonatomic) FloatingWindow *floatWindow;
@property (nonatomic, strong) JSGController * _Nullable jsyuyinctr;




@property (nonatomic) BOOL isNotification;

@property (nonatomic, assign) NSInteger badgeCount;
@property (nonatomic, assign) NSInteger addFriendBadgeCount;

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    app = self;
    BuglyConfig *config = [[BuglyConfig alloc] init];
    config.reportLogLevel = BuglyLogLevelVerbose;
    [Bugly startWithAppId:@"1d9e6b546a" config:config];
    self.isJitsiMeet=false;
    _isNotification=false;
    self.shouldShowLock = YES;
    self.bgMark=@"";
    
    
    [self initJSMSDK];
    [self setupListener];
    [self checkLoginState:launchOptions];
    [self registerPushright];
    [self setupCallProvider];
    [self startNetworkReachability];
    _isTokenCleared=YES;
    
    _floatWindow = [[FloatingWindow alloc] initWithFrame:self.window.bounds];
    [_floatWindow hide];
    self.bgMark = @"";
    
    NSLog(@"didFinishLaunchingWithOptions------");
    
    
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayAndRecord mode:AVAudioSessionModeVoiceChat options:AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowBluetoothA2DP | AVAudioSessionCategoryOptionAllowAirPlay error:nil];
    [session setActive:YES error:nil];
    
    
#ifdef DEBUG
        //默认
        [[DoraemonManager shareInstance] install];
        // 或者使用传入位置,解决遮挡关键区域,减少频繁移动
        //[[DoraemonManager shareInstance] installWithStartingPosition:CGPointMake(66, 66)];
    #endif
    
    return YES;
}




-(void)applicationDidBecomeActive:(UIApplication *)application{
    NSLog(@"applicationDidBecomeActive");
   
    if(self.isLogin){
        [self sartWebsocket];
        if(self.isJitsiMeet){
            [_floatWindow viewInFload:0];
        }
        [self showLockScreen];
        if(!_isNotification){
            if ([[self.window jk_currentViewController] isKindOfClass:UITabBarController.class]){
                UITabBarController * tabbarVc= (UITabBarController *)[self.window jk_currentViewController];
                if (tabbarVc.selectedIndex==0) {
                    ChatIndexController * chatListVc = tabbarVc.viewControllers[0];
                    if (chatListVc) {
                        [chatListVc reloadList];
                    }
                }
            }
            else{
                [Bugly reportException:[NSException exceptionWithName:@"applicationDidBecomeActive1" reason:@"1" userInfo:nil]];
                if ([[self.window jk_currentViewController] isKindOfClass:ChatController.class]) {
                    ChatController * currentChatVc = (ChatController *)[self.window jk_currentViewController];
                    [currentChatVc reloadAllData];
                    [Bugly reportException:[NSException exceptionWithName:@"applicationDidBecomeActive2" reason:@"2" userInfo:nil]];
                }
            }
        }
    }
}
-(void)applicationDidEnterBackground:(UIApplication *)application{
    NSLog(@"applicationDidEnterBackground");
    _isNotification=false;
//    [self endWebsocket];
    __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
            [application endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // 在这里保持任务运行或等待事件，例如等待来电等。
            [application endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        });
    // 应用进入后台时标记需要显示锁屏
    
    if(self.isJitsiMeet == YES){
        [self.window endEditing:YES];
    }
    else{
        if ([[APPLocker sharedLocker] isPasswordSet] && [[APPLocker sharedLocker] isLockEnabled]) {
            self.shouldShowLock = YES;
        }
    }
}

+ (instancetype)sharedInstance {
    return app;
}

-(void)initJSMSDK{
    
    JitsiMeetConferenceOptions *defaultOptions
        = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
            builder.serverURL = [NSURL URLWithString:JitsiMeetSV];
            [builder setFeatureFlag:@"welcomepage.enabled" withBoolean:NO];
            [builder setFeatureFlag:@"prejoinPage.enabled" withBoolean:NO];
            //媒体流优化
            builder.audioMuted = NO;  // 提前初始化音频模块
            builder.videoMuted = NO;  // 提前初始化视频模块
            //禁用非必要功能（减少初始化负载）
            [builder setFeatureFlag:@"add-people.enabled" withBoolean:NO];
            [builder setFeatureFlag:@"invite.enabled" withBoolean:NO];
            [builder setFeatureFlag:@"live-streaming.enabled" withBoolean:NO];
            [builder setFeatureFlag:@"video-share.enabled" withBoolean:NO];
            [builder setFeatureFlag:@"call-integration.enabled" withBoolean:NO];
            [builder setFeatureFlag:@"startWithAudioMuted" withBoolean:NO];
            [builder setFeatureFlag:@"recording.enabled" withBoolean:NO];
            [builder setFeatureFlag:@"kick-out.enabled" withBoolean:NO];
            [builder setFeatureFlag:@"security-options.enabled" withBoolean:NO];
            

//
//            //网络传输层加速
//            [builder setConfigOverride:@"disableSimulcast" withBoolean:YES];
//            [builder setFeatureFlag:@"reconnect.enabled" withBoolean:YES];
//            [builder setFeatureFlag:@"websocket-keep-alive.enabled" withBoolean:YES];
//            [builder setFeatureFlag:@"network-monitor.enabled" withBoolean:YES];
//            [builder setConfigOverride:@"iceTransportPolicy" withValue:@"relay"];
//            // 界面渲染加速
//            [builder setFeatureFlag:@"filmstrip.enabled" withBoolean:NO];
//            [builder setFeatureFlag:@"tile-view.enabled" withBoolean:NO];
//            
//            [builder setFeatureFlag:@"pip.enabled" withBoolean:NO];
//            [builder setFeatureFlag:@"chat.enabled" withBoolean:NO];
            [builder setConfigOverride:@"toolbarButtons" withArray:@[@"microphone",@"camera"]];
        }];
    [JitsiMeet sharedInstance].defaultConferenceOptions = defaultOptions;
    UIStoryboard *board = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    _jsyuyinctr = [board instantiateViewControllerWithIdentifier:@"JSGController"];
    _jsyuyinctr.modalPresentationStyle = UIModalPresentationFullScreen;
}

-(void)setupListener{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onLoginSucc) name:nkonLoginSucc object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onLogoutSucc) name:nkonLogoutSucc object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addFriend) name:nkonAddFriendNote object:nil];;
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Failed to get token, error: %@", error);
}


#pragma mark push token voip token

-(void)registerPushright{
    // 请求推送权限
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    center.delegate = self; // 设置代理以处理通知相关事件
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionProvidesAppNotificationSettings) completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            // 用户授权成功
            dispatch_async(dispatch_get_main_queue(), ^{
                [[UIApplication sharedApplication] registerForRemoteNotifications];
            });
        } else {
            // 用户授权失败
        }
    }];
    PKPushRegistry *registry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
    registry.delegate = self;
    registry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}


- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    // 将NSData转换为NSString以便于传输或存储
   
    NSRange range = NSMakeRange(0, 16); // 例如，从索引0开始，获取前10个字节
    NSData *subData1 = [deviceToken subdataWithRange:range];
    range = NSMakeRange(16, 16);
    NSData *subData2 = [deviceToken subdataWithRange:range];
    range = NSMakeRange(24, 32);
    NSString *token1=[[subData1 description] substringWithRange:range];
    NSString *token2=[[subData2 description] substringWithRange:range];
    NSString *token = [NSString stringWithFormat:@"%@%@",token1,token2];
    NSLog(@"%@",token);
    // 将token发送到你的服务器或其他需要的地方
    [UDManager.shareInstance setSDManager:token key:dkpushtoken];
    NSString *bgMark = [NSString stringWithFormat:@"推送token：%ld",token.length];
    [Bugly reportException:[NSException exceptionWithName:bgMark reason:@"" userInfo:nil]];
    if(self.isLogin){
        [self updivicetoken];
    }
}

#pragma mark login sttate
- (void)checkLoginState:(NSDictionary *)launchOptions{
    [[LoginStateManager sharedManager] getUserInfo];
    [LoginStateManager sharedManager].checkLoginState = ^(BOOL isLogin) {
        if (isLogin) {
            self.isLogin =TRUE;
            
            [self updivicetoken];
            [self updiviceVoIPtoken];
            [self sartWebsocket];
            [self openFMDB];
            [self openMainController];
            // 检查是否需要显示启动锁屏
            if ([[APPLocker sharedLocker] isPasswordSet] && [[APPLocker sharedLocker] isLockEnabled]) {
                [self showLockScreen];
            }
            else{
                self.shouldShowLock = NO;
            }
        }else{
            [self openLoginController];
        }
    };
}

-(void)updivicetoken{
    NSString *token =[UDManager.shareInstance getSDManager:dkpushtoken];
    NSDictionary *usinfo = [UDManager.shareInstance getDDManager:dkuserinfo];
    NSLog(@"dkpushtoken:%@",token);
    NSDictionary *ud=@{
        @"registrationId": token?:@"",
        @"userId":usinfo[@"id"]?:@"",
        @"platformType":@"i"
    };
    NSString *bgMark = [NSString stringWithFormat:@"上传推送token：%ld",token.length];
    [Bugly reportException:[NSException exceptionWithName:bgMark reason:@"" userInfo:nil]];
    [UserNetApi setUserinfo:ud succ:^(int code, NSDictionary * res) {
        self->_isTokenCleared=NO;
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:res options:0 error:nil];
        if (!jsonData) {
            NSLog(@"Got an error:");
        } else {
            NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
            NSLog(@"%@", jsonString); // 输出：{"name":"John","age":25}
        }
    } fail:^(NSError * _Nonnull error) {
        NSLog(@"--%@",error);
    }];
}
-(void)updiviceVoIPtoken{
    NSString *token =[UDManager.shareInstance getSDManager:dkvoiptoken];
    NSDictionary *usinfo = [UDManager.shareInstance getDDManager:dkuserinfo];
    NSLog(@"dkvoiptoken:%@",token);
    NSString *bgMark = [NSString stringWithFormat:@"上传 voip 推送token：%ld",token.length];
    [Bugly reportException:[NSException exceptionWithName:bgMark reason:@"" userInfo:nil]];
    if([token isKindOfClass:[NSNull class]]){
        return;
    }
    NSDictionary *ud=@{
        @"voipTk": token?:@"",
        @"userId":usinfo[@"id"]?:@"",
        @"platformType":@"i"
    };
    
    [UserNetApi setUserinfo:ud succ:^(int code, NSDictionary * res) {
        NSLog(@"updiviceVoIPtoken:%@",[res description]);
        self->_isTokenCleared=NO;
    } fail:^(NSError * _Nonnull error) {
        NSLog(@"--%@",error);
    }];
}

- (void)addFriend{
    self.addFriendBadgeCount++;
    NSLog(@"addFriend------------:%ld", self.addFriendBadgeCount);
    [self updateTabBarBadgeValueAtIndex:1 badgeCount:self.addFriendBadgeCount];

    [self sendAddFreindNotice];
    [self updateApplicationIconBadgeNumber];
}

- (void)sendAddFreindNotice {
    // 发送本地通知
    UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
    content.title = @"好友申请";
    content.body = @"您收到了新的好友申请";
    content.sound = [UNNotificationSound defaultSound];
    content.badge = @(self.addFriendBadgeCount);
    content.userInfo = @{
        @"addFriend":@(1)
    };
    UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.1 repeats:NO];
    
    NSString *identifier = [NSString stringWithFormat:@"FriendRequest_%@", [[NSUUID UUID] UUIDString]];
    UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
    
    [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
        if (error) {
            NSLog(@"发送本地通知失败: %@", error);
        } else {
            NSLog(@"发送本地通知成功");
        }
    }];
}

- (void)updateApplicationIconBadgeNumber {
    NSInteger total = self.badgeCount + self.addFriendBadgeCount;
    if (@available(iOS 16.0, *)) {
        [[UNUserNotificationCenter currentNotificationCenter] setBadgeCount:total withCompletionHandler:^(NSError * _Nullable error) {
            if (error) {
                NSLog(@"设置消息未读数 error: %@", error);
            }
        }];
    } else {
        // Fallback on earlier versions
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:total];
    }
}

- (void)resetAddFriendBadgeCount {
    self.addFriendBadgeCount = 0;
    [self updateTabBarBadgeValueAtIndex:1 badgeCount:0];
    [self updateApplicationIconBadgeNumber];
}

- (void)resetBadgeCount {
    self.badgeCount = 0;
    [self updateApplicationIconBadgeNumber];
}

- (void)updateTabBarBadgeValueAtIndex:(NSInteger)index badgeCount:(NSInteger)badgeCount {
    UITabBarController * tabbarVc = (UITabBarController *)self.window.rootViewController;
    if (![tabbarVc isKindOfClass:[UITabBarController class]]) {
        return;
    }
    if(index < 0 || index >= tabbarVc.tabBar.items.count){
        return;
    }
    UITabBarItem *tabBarItem = tabbarVc.tabBar.items[index];
    NSString *badgeValue = badgeCount > 0 ? [NSString stringWithFormat:@"%ld", badgeCount] : nil;
    badgeValue = badgeValue.length > 2 ? @"99+" : badgeValue;
    tabBarItem.badgeValue = badgeValue;
}

- (void)updateBadgeCount:(NSInteger)badgeCount {
    self.badgeCount = badgeCount;
    [self updateApplicationIconBadgeNumber];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    NSLog(@"Received notification: %@", userInfo);
    
    NSDictionary *temp =userInfo[@"imMsg"];
    if(temp){
        if ([temp jk_hasKey:@"addFriend"]) {
            [self addFriend];
        }
        NSDictionary *msg =temp[@"message"];
        NSString *msgtype=msg[@"msgtype"];
        if([msgtype isEqualToString:@"close"]){
            if(self.uuid!=nil){
                NSString *fromId = self.msg[@"fromId"];
                if ( [fromId isEqualToString:msg[@"fromId"]]) {
                    
                    [self.callProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonDeclinedElsewhere];
                    self.uuid = nil;
                    self.msg =nil;
                }
            }
        }
    }
    
    // 处理推送消息，例如更新UI或处理数据等
    completionHandler(UIBackgroundFetchResultNewData);
}

#pragma mark - PKPushRegistryDelegate
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
    // 处理推送凭证更新，例如保存 token 到服务器
    NSLog(@"Credentials updated: %@", credentials.token);
    NSData *deviceToken = (NSData *)credentials.token;
    NSRange range = NSMakeRange(0, 16); // 例如，从索引0开始，获取前10个字节
    NSData *subData1 = [deviceToken subdataWithRange:range];
    range = NSMakeRange(16, 16);
    NSData *subData2 = [deviceToken subdataWithRange:range];
    range = NSMakeRange(24, 32);
    //NSLog(@"subData1: %@",subData1);
    //NSLog(@"subData2: %@",subData2);
    NSString *token1=[[subData1 description] substringWithRange:range];
    NSString *token2=[[subData2 description] substringWithRange:range];
    NSString *token = [NSString stringWithFormat:@"%@%@",token1,token2];
    NSLog(@"%@",token);
     //将token发送到你的服务器或其他需要的地方
    NSString *bgMark = [NSString stringWithFormat:@"voip token：%ld",token.length];
    [Bugly reportException:[NSException exceptionWithName:bgMark reason:@"" userInfo:nil]];
    [UDManager.shareInstance setSDManager:token key:dkvoiptoken];
    if(self.isLogin){
        [self updiviceVoIPtoken];
    }
}
 
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion{
    
    
    
    NSDictionary * temp =payload.dictionaryPayload;
    temp =temp[@"business"];
    temp=temp[@"incomingCallParams"];
    NSString *name =temp[@"localizedCallerName"];
    NSLog(@"name:%@",name);
    
    temp =payload.dictionaryPayload;
    temp =temp[@"imMsg"];
    if(self.uuid!=nil||self.isJitsiMeet){//通知对方正忙,功能需要补上
        [self isBUSYNow:temp[@"message"]];
        return;
    }
    self.msg = temp[@"message"];
    NSLog(@"self.msg-----:%@",self.msg);
    CXCallUpdate * callUpdate = [[CXCallUpdate alloc]init];
    callUpdate.supportsGrouping = YES;
    callUpdate.supportsDTMF = YES;
    callUpdate.hasVideo = YES;
    callUpdate.supportsHolding = YES;
    [callUpdate setLocalizedCallerName:name];
    CXHandle * handle = [[CXHandle alloc]initWithType:CXHandleTypePhoneNumber value:@""];
    callUpdate.remoteHandle = handle;
    self.uuid = [NSUUID UUID];
    
    [self.callProvider reportNewIncomingCallWithUUID:self.uuid update:callUpdate completion:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    }];
    
    completion();
}

-(void)isBUSYNow:(NSDictionary *)msg{
    
    NSDate *now = [NSDate date];
    NSTimeInterval trt = [now timeIntervalSince1970];
    NSInteger time = trt*1000;
    NSString *strtime = [NSString stringWithFormat:@"%ld",(long)time];
    NSDictionary *callMsg = @{
        @"code":SendCode_WEBRTC_DFBUSY,
        @"message": @{
            @"chatId":msg[@"fromId"],
            @"fromId":msg[@"chatId"],
            @"type":@"0",
            @"messageType":MessageType_DFBUSY,
            @"timestamp":strtime,
            @"payload":@""
        }
    };
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:callMsg options:0 error:&error];
    if (!jsonData) {
        NSLog(@"Got an error: %@", error);
    } else {
        NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        NSLog(@"%@", jsonString); // 输出: {"name":"John","age":25}
        [GWebSocket.shareInstance sendMsg:jsonString];
    }
}

#pragma mark - CXProviderDelegate Methods

- (void)setupCallProvider {
    
    // 创建配置对象
    CXProviderConfiguration *config = [[CXProviderConfiguration alloc] init];
    config.supportsVideo = YES; // 是否支持视频通话
    config.maximumCallGroups = 1; // 最大通话组数
    config.maximumCallsPerCallGroup = 1; // 每个通话组的最大通话数
    config.supportedHandleTypes = [[NSSet alloc] initWithObjects:[NSNumber numberWithInt:CXHandleTypeGeneric],[NSNumber numberWithInt:CXHandleTypePhoneNumber], nil];//[NSSet setWithArray:@[CXHandleTypePhoneNumber]]; // 支持的号码类型
    config.iconTemplateImageData = UIImagePNGRepresentation([UIImage imageNamed:@"AppIcon"]); // 应用图标
    config.ringtoneSound = @"ringtone.aiff"; // 铃声文件（可选）
    
    // 创建CXProvider实例
    self.callProvider = [[CXProvider alloc] initWithConfiguration:config];
    [self.callProvider setDelegate:self queue:nil];
    //self.callRoomMap = [NSMutableDictionary dictionary];
    
    
}

- (void)providerDidReset:(CXProvider *)provider {
    NSLog(@"Provider reset");
}
 
- (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action {
    // 开始通话的逻辑，如连接服务器等
    NSLog(@"performStartCallAction:%@",action);
    [action fulfill]; // 当通话开始时调用此方法完成action
}

-(void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action{
    
    
    [self reciveVoip];
    
    //使用GCD创建一个在3秒后执行的定时器
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"performAnswerCallAction:%@",action);
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
            // 应用已经解锁并且在前台
            if(self.uuid){
                
                [self.callProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonDeclinedElsewhere];
                self.msg = nil;
                self.uuid = nil;
            }
        }
    });

}
-(void)provider:(CXProvider *)provider timedOutPerformingAction:(CXAction *)action{
    
    if (!self.uuid) {
        return;
    }
    
    [self.callProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonDeclinedElsewhere];
    self.msg = nil;
    self.uuid = nil;
    NSLog(@"timedOutPerformingAction:%@",action);
}
- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action {
    // 挂断电话的逻辑，如断开服务器连接等
    NSLog(@"performEndCallAction:%@",action);
    NSDate *now = [NSDate date];
    NSTimeInterval trt = [now timeIntervalSince1970];
    NSInteger time = trt*1000;
    NSString *strtime = [NSString stringWithFormat:@"%ld",(long)time];
    NSDictionary *callMsg = @{
        @"code":@"9",
        @"message": @{
            @"chatId":self.msg[@"fromId"],
            @"fromId":self.msg[@"chatId"],
            @"type":@"0",
            @"msgtype":@"close",
            @"timestamp":strtime,
            @"payload":self.msg[@"payload"]
        }
    };
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:callMsg options:0 error:&error];
    if (!jsonData) {
        NSLog(@"Got an error: %@", error);
    } else {
        NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        NSLog(@"%@", jsonString); // 输出: {"name":"John","age":25}
        [GWebSocket.shareInstance sendMsg:jsonString];
    }
    self.uuid = nil;
    self.msg =nil;
    
    [action fulfill]; // 当通话结束时调用此方法完成action
}

-(void)reciveVoip{
    NSLog(@"reciveVoip-------------1");
    if(self.msg){
        NSNumber *conetType = self.msg[@"conetType"];
        NSLog(@"vidio:%@",self.msg[@"payload"]);
        BOOL audioOnly = YES;
        if(conetType.boolValue){
            audioOnly = NO;
        }
        else{
            audioOnly = YES;
        }
        
        [self startJSCall:self.msg[@"fromId"] room:self.msg[@"payload"] isCaller:NO audioOnly:audioOnly];
    }
}

//开启悬浮窗拨打方式
-(void)startJSCall:(NSString *_Nonnull)chatId room:(NSString *_Nonnull)roomId isCaller:(BOOL)isCaller audioOnly:(BOOL)audioOnly{
    
    self.isJitsiMeet = YES;
    if(_jsyuyinctr){
        _jsyuyinctr.chatId = chatId.copy;
        _jsyuyinctr.room = roomId.copy;
        _jsyuyinctr.audioOnly = audioOnly;
        _jsyuyinctr.isCaller = isCaller;
    }
    else{
        UIStoryboard *board = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
        _jsyuyinctr = [board instantiateViewControllerWithIdentifier:@"JSGController"];
        _jsyuyinctr.modalPresentationStyle = UIModalPresentationFullScreen;
        _jsyuyinctr.chatId = chatId.copy;
        _jsyuyinctr.room = roomId.copy;
        _jsyuyinctr.audioOnly = audioOnly;
        _jsyuyinctr.isCaller = isCaller;
    }
    NSLog(@"startJSCall roomId:%@",roomId);
    [_floatWindow showView:_jsyuyinctr.view];
    [_jsyuyinctr startJitsiMeetCall];
    [[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
}

-(void)floadinSmWindow:(NSInteger )type{
    if(type!=0){
        [_floatWindow viewInFload:type];
    }
    
}

+(void)closeVoip{
    if(app.uuid!=nil){
        [app.callProvider reportCallWithUUID:app.uuid endedAtDate:nil reason:CXCallEndedReasonDeclinedElsewhere];
        app.uuid = nil;
        app.msg =nil;
    }
}

+(void)JitsiMeetState:(BOOL)state{
    app.isJitsiMeet=state;
    if(!state){
        if(app.shouldShowLock){
            [app showLockScreen];
        }
        else{
            [app.floatWindow hide];
        }
    }
}
+(void)unlockAPP{
    app.shouldShowLock=NO;
}

+(void)changeFloadViewState:(BOOL)state{
    if (state) {
        [app.floatWindow hide];
    }
    else{
        if ([[APPLocker sharedLocker] isPasswordSet] && [[APPLocker sharedLocker] isLockEnabled]) {
            [app.floatWindow show:1];
        }
    }
}

#pragma mark 用户点击消息推送或滑动
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    
    NSDictionary *userInfo = notification.request.content.userInfo;
    NSInteger addFriend = [[userInfo objectForKey:@"addFriend"] integerValue];
    if (addFriend) {
        // 添加好友通知在app内也要展示
        completionHandler(UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner |
                              UNNotificationPresentationOptionSound |
                              UNNotificationPresentationOptionBadge);
    }
    
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {
    
    // 处理用户对通知的响应（点击、滑动等）
    if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) {
        // 用户点击了通知
        NSDictionary *userInfo = response.notification.request.content.userInfo;
        [self handleNotification:userInfo];
        NSLog(@"userInfo: %@", userInfo);
    } else if ([response.actionIdentifier isEqualToString:@"customActionIdentifier"]) {
        // 处理自定义动作（如果有的话）
    }
    completionHandler(); // 调用完成处理程序以结束操作
}


- (void)handleNotification:(NSDictionary *)userInfo {
    NSDictionary * tempDict = userInfo[@"imMsg"];
    NSDictionary * imMsg = tempDict[@"message"];
    _isNotification=true;
    NSMutableDictionary * mutablemsg = imMsg.mutableCopy;
    NSLog(@"------mutablemsg:%@",mutablemsg);
    NSDictionary * user = [UDManager.shareInstance getDDManager:dkuserinfo];
    if([user[@"id"] isEqual:imMsg[@"fromId"]]){
        [mutablemsg setObject:@"true" forKey:@"mine"];
    }else{
        if([Friendchat isEqual:imMsg[@"type"]]){
            [mutablemsg setObject:imMsg[@"fromId"] forKey:@"chatId"];
        }
    }
    
    if (imMsg) {
        if (![LoginStateManager sharedManager].isLoggedIn) {
            return;
        }
        
        if ([imMsg jk_hasKey:@"addFriend"]) {
            return;
        }
        
        
        NSString *strtype = mutablemsg[@"type"];
        NSInteger type = [strtype integerValue];
        NSString *chatId = mutablemsg[@"chatId"];
        NSString *titlename = mutablemsg[@"fromName"]?:@"";
        NSString *avatar = mutablemsg[@"fromAvatar"]?:@"";
        
        
//        NSLog(@"top className:%@",[[self.window jk_topMostController] class]);
//        NSLog(@"current className:%@",[[self.window jk_currentViewController] class]);
        if ([[self.window jk_currentViewController] isKindOfClass:ChatController.class]) {
            ChatController * currentChatVc = (ChatController *)[self.window jk_currentViewController];
            if (![currentChatVc.chatId isEqualToString:mutablemsg[@"chatId"]]) {
                currentChatVc.chatId = chatId;
                currentChatVc.type = type;
                currentChatVc.titlename = titlename;
                currentChatVc.avatar = avatar;
                [currentChatVc reloadAllData];
                return;
            }
            else{
                currentChatVc.chatId = chatId;
                currentChatVc.type = type;
                currentChatVc.titlename = titlename;
                currentChatVc.avatar = avatar;
                [currentChatVc reloadAllData];
                return;
            }
        }
        
        UIStoryboard *board = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
        ChatController *chatctr = [board instantiateViewControllerWithIdentifier:@"ChatController"];
        UINavigationController *uiNavC = [[UINavigationController alloc] initWithRootViewController:chatctr];
        uiNavC.modalPresentationStyle = UIModalPresentationFullScreen;
        chatctr.chatId = chatId;
        chatctr.type = type;
        chatctr.titlename = titlename;
        chatctr.avatar = avatar;
        UITabBarController * tabbarVc = (UITabBarController *)self.window.rootViewController;
        ChatIndexController * chatListVc = tabbarVc.viewControllers[0];
        if (chatListVc) {
            [chatListVc presentViewController:uiNavC animated:YES completion:nil];
        }
    }
}

#pragma mark -user state and note

-(void)onLoginSucc{
    self.isLogin =TRUE;
    [self openFMDB];
    [self openMainController];
    [self updivicetoken];
    [self updiviceVoIPtoken];
    [self sartWebsocket];
}
-(void)onLogoutSucc{
    self.isLogin =false;
    NSLog(@"1-----------------1");
//        [GDBManager.shareInstance delLocalmsglistTable:userid];
//        [GDBManager.shareInstance delchatlistTable:nil fail:nil];
//        [GDBManager.shareInstance deleteDB];
    [UDManager.shareInstance removeUDManager:gkeytoken];
    [UDManager.shareInstance removeUDManager:dkuserloginId];
    [UDManager.shareInstance removeUDManager:dkuserinfo];
    [UDManager.shareInstance removeUDManager:dkuserId];
    [self clearVoipToken];
    [self openLoginController];
    [self endWebsocket];
    [self resetBadgeCount];
    [self resetAddFriendBadgeCount];
}

-(void)clearVoipToken{
    
    NSString *voiptoken = [UDManager.shareInstance getSDManager:dkvoiptoken];
    NSLog(@"voiptoken:%@",voiptoken);
    if([voiptoken isKindOfClass:[NSString class]]&&voiptoken.length>10){
        NSDictionary *dic = @{
            @"voipTk":voiptoken
        };
        [UserNetApi clearVoipTk:dic succ:^(int code, NSDictionary * res) {
            NSLog(@"clearVoipTk:%@",res);
            self->_isTokenCleared=YES;
        } fail:^(NSError * _Nonnull error) {
            
        }];
    }
    
    NSString *pushtoken = [UDManager.shareInstance getSDManager:dkpushtoken];
    NSLog(@"voiptoken:%@",pushtoken);
    if([pushtoken isKindOfClass:[NSString class]]&&pushtoken.length>10){
        NSDictionary *dic = @{
            @"registrationId":pushtoken
        };
        [UserNetApi clearRegistrationId:dic succ:^(int code, NSDictionary * res) {
            NSLog(@"clearRegistrationId:%@",res);
            self->_isTokenCleared=YES;
        } fail:^(NSError * _Nonnull error) {
            
        }];
    }
}



#pragma mark mainControllor Manager
-(void)openMainController{
    NSLog(@"openMainController");
    UIStoryboard *board = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    UITabBarController *tbc = [board instantiateViewControllerWithIdentifier:@"GTabBarController"];
    //UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:tbc];
    NSArray *ctrs = tbc.viewControllers;
    //------------1
    UIViewController *time = ctrs[0];
    // 创建一个新的 UITabBarItem
    UIImage *index = [[UIImage imageNamed:@"index"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UIImage *index_cur = [[UIImage imageNamed:@"index_cur"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UITabBarItem *tabBarItem = [[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"TabBarItem1", @"")
                                                             image:index
                                                     selectedImage:index_cur];
    // 设置标签文本
    tabBarItem.title = NSLocalizedString(@"TabBarItem1", @"");
     
    // 设置标签的文本颜色
    [tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateNormal];
    [tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateSelected];
    [time setTabBarItem:tabBarItem];
    //----------------2
    time = ctrs[1];
    // 创建一个新的 UITabBarItem
    UIImage *index1 = [[UIImage imageNamed:@"txl"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UIImage *index_cur1 = [[UIImage imageNamed:@"txl_cur"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UITabBarItem *tabBarItem1 = [[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"TabBarItem2", @"")
                                                             image:index1
                                                     selectedImage:index_cur1];
    // 设置标签文本
    tabBarItem1.title = NSLocalizedString(@"TabBarItem2", @"");
     
    // 设置标签的文本颜色
    [tabBarItem1 setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateNormal];
    [tabBarItem1 setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateSelected];
    [time setTabBarItem:tabBarItem1];
    //------------------3
    time = ctrs[2];
    // 创建一个新的 UITabBarItem
    UIImage *index2 = [[UIImage imageNamed:@"qunzu"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UIImage *index_cur2 = [[UIImage imageNamed:@"qunzu_cur"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UITabBarItem *tabBarItem2 = [[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"TabBarItem3", @"")
                                                             image:index2
                                                     selectedImage:index_cur2];
    // 设置标签文本
    tabBarItem2.title = NSLocalizedString(@"TabBarItem3", @"");
     
    // 设置标签的文本颜色
    [tabBarItem2 setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateNormal];
    [tabBarItem2 setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateSelected];
    [time setTabBarItem:tabBarItem2];
    //------------------4
    time = ctrs[3];
    // 创建一个新的 UITabBarItem
    UIImage *index3 = [[UIImage imageNamed:@"wode"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UIImage *index_cur3 = [[UIImage imageNamed:@"wode_cur"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UITabBarItem *tabBarItem3 = [[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"TabBarItem4", @"")
                                                             image:index3
                                                     selectedImage:index_cur3];
    // 设置标签文本
    tabBarItem3.title = NSLocalizedString(@"TabBarItem4", @"");
     
    // 设置标签的文本颜色
    [tabBarItem3 setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateNormal];
    [tabBarItem3 setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateSelected];
    [time setTabBarItem:tabBarItem3];
    
    
    self.window.rootViewController = tbc;
}
-(void)openLoginController{
    UIStoryboard *board = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    GLoginController *login = [board instantiateViewControllerWithIdentifier:@"LoginController"];
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:login];
    self.window.rootViewController = nav;
}


#pragma mark openSocket

-(void)sartWebsocket{
    NSLog(@"----------------sartWebsocket");
    [[GWebSocket shareInstance] connectWebSocket];
}

-(void)endWebsocket{
    [[GWebSocket shareInstance] closeWebSocket];
}

#pragma mark init DB
-(void)openFMDB{
    [GDBManager.shareInstance createDatabase:^(NSArray * _Nullable array) {
        [GDBManager.shareInstance createLocalMSGtable:^(NSArray * _Nullable array) {
        } fail:^(NSString * _Nullable error) {
        }];
        [GDBManager.shareInstance createChattable:^(NSArray * _Nullable array) {
        } fail:^(NSString * _Nullable error) {
        }];
        [GDBManager.shareInstance createLastreadtimetable:^(NSArray * _Nullable array) {
        } fail:^(NSString * _Nullable error) {
        }];
    } fail:^(NSString * _Nullable error) {
        
    }];
}


#pragma mark - UISceneSession lifecycle


//- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
//    // Called when a new scene session is being created.
//    // Use this method to select a configuration to create the new scene with.
//    return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
//}
//
//
//- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
//    // Called when the user discards a scene session.
//    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
//    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
//}


#pragma mark - Core Data stack

@synthesize persistentContainer = _persistentContainer;

- (NSPersistentContainer *)persistentContainer {
    // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
    @synchronized (self) {
        if (_persistentContainer == nil) {
            _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"555IM"];
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                    // Replace this implementation with code to handle the error appropriately.
                    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                    
                    /*
                     Typical reasons for an error here include:
                     * The parent directory does not exist, cannot be created, or disallows writing.
                     * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                     * The device is out of space.
                     * The store could not be migrated to the current model version.
                     Check the error message to determine what the actual problem was.
                    */
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    abort();
                }
            }];
        }
    }
    
    return _persistentContainer;
}

#pragma mark - Core Data Saving support

- (void)saveContext {
    NSManagedObjectContext *context = self.persistentContainer.viewContext;
    NSError *error = nil;
    if ([context hasChanges] && ![context save:&error]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, error.userInfo);
        abort();
    }
}

#pragma mark 检测网络状态
-(void)startNetworkReachability {
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
    __weak typeof(manager) weakManager = manager;
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        BOOL isReachable = weakManager.isReachable;
        self->_isReachable = isReachable;
        NSLog(@"startNetworkReachability: %d", isReachable);
        if (isReachable) {
            
        } else {
            
        }
    }];
    
    [manager startMonitoring];
}

- (BOOL)isReachable {
    return _isReachable;
}

#pragma mark applock
- (void)showLockScreen {
    // 确保在主线程执行
    if (self.shouldShowLock && [[APPLocker sharedLocker] isPasswordSet] && [[APPLocker sharedLocker] isLockEnabled]) {
        NSLog(@"showLockScreen--------------1");
        if (self.isJitsiMeet) {
            [_floatWindow viewInFload:0];
            return;
        }
        else{
            [_floatWindow show:1];
        }
        return;
    }
    
    if (!self.isJitsiMeet) {
        [_floatWindow hide];
    }
}

- (void)applicationWillTerminate:(UIApplication *)application {
    [[OSSManager sharedManager] applicationWillTerminate];
}


@end
