//
//  GWebSocket.m
//  TUIContact
//
//  Created by gan on 2025/3/24.
//

#import <Foundation/Foundation.h>
#import "GWebSocket.h"
#import <AFNetworking/AFNetworkReachabilityManager.h>
#import "GDBManager.h"
#import "ChatListStore.h"
#import "ChatsStore.h"
#import "WebRTCStore.h"
#import "UserNetApi.h"
#import "LoginStateManager.h"

static int const kHeartbeatDuration = 10;
static int const timeoutError = 5;

static NSString *ping = @"{\"code\":0}";
static NSString *redeady = @"{\"code\":1}";


@interface GWebSocket ()<SRWebSocketDelegate>
@property (nonatomic,strong) SRWebSocket *socket;
@property (strong, nonatomic) NSTimer *heatBeat;

@property (nonatomic,strong) NSString *serverIpString;
@property (nonatomic,strong) NSString *userid;
@property (nonatomic,strong) NSString *UUID;
@end


@implementation GWebSocket
{
    BOOL _isReachable;
}
+ (GWebSocket *_Nonnull)shareInstance{
    static id gShareInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
      gShareInstance = [[self alloc] init];
    });
    return gShareInstance;
}

- (instancetype)init {
    if (self = [super init]) {
        NSUUID *uid = [NSUUID UUID];
        _UUID=uid.UUIDString;
        NSLog(@"_UUID:%@",_UUID);
        [self startNetworkReachability];
        [self startHeartbeat];
        [self addObserver];
    }
    return self;
}

#pragma mark - Public -
- (void)connectWebSocket {
    [self initWebSocket];
}
- (void)closeWebSocket {
//    _UUID=nil;
    [self close];
}

- (void)sendMsg:(NSString *)msg {
    if (self.socket && self.socket.readyState == SR_OPEN) {
        // 只有在socket状态为SR_OPEN 时，才可以发送消息
        // 在socket状态不为SR_OPEN，可以将消息放进队列里，在websocket连上时，再发送
        NSLog(@"sendMsg:%@",msg);
        [self.socket sendString:msg error:nil];
    }
    else{
        NSLog(@"socket--------不可用");
        [self reConnectSocket];
    }
//    NSLog(@"_UUID:%@",_UUID);
}



#pragma mark -- WebSocket
//初始化 WebSocket
- (void)initWebSocket{
    NSDictionary *userinfo =[UDManager.shareInstance getDDManager:dkuserinfo];
    self.userid =userinfo[@"id"];
    
    NSString *token = (NSString *)[UDManager.shareInstance getSDManager:gkeytoken];
    if(_UUID==nil){
        NSUUID *uid = [NSUUID UUID];
        _UUID=uid.UUIDString;
    }
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@token=%@&client=mobile&uuid=%@",WebSocketUrl,token,_UUID]];
    //请求
    //NSLog(@"url:%@",url);
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
    //初始化请求`
    _socket = [[SRWebSocket alloc] initWithURLRequest:request];
    
    //代理协议`
    _socket.delegate = self;
    //直接连接
    [_socket open];
}

-(void)sendReady{
    NSLog(@"------%@",redeady);
    [self.socket sendString:redeady error:nil];
}
-(void)sendPing{
    [self.socket sendString:ping error:nil];
}

#pragma mark - Heart Timer -

- (void)addObserver {
    // 进入后台
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(appDidEnterBackground)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
    
    // 回到前台
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(appWillEnterForeground)
                                                 name:UIApplicationWillEnterForegroundNotification
                                               object:nil];
}

- (void)appDidEnterBackground {
    [self destoryHeartbeat];
}

- (void)appWillEnterForeground {
    [self startHeartbeat];
    [self checkReconnectIfNeed];
}


//保活机制 探测包
- (void)startHeartbeat {
    self.heatBeat = [NSTimer scheduledTimerWithTimeInterval:kHeartbeatDuration
                                                     target:self
                                                   selector:@selector(heartbeatAction)
                                                   userInfo:nil
                                                    repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.heatBeat forMode:NSRunLoopCommonModes];
}


//断开连接时销毁心跳
- (void)destoryHeartbeat{
    [_heatBeat invalidate];
    _heatBeat = nil;
}

// 发送心跳
- (void)heartbeatAction {
    NSLog(@"XTWebSocket heartbeatAction readyState: %ld", self.socket.readyState);

    BOOL isLoggedIn = [LoginStateManager sharedManager].isLoggedIn;
    if (!isLoggedIn) {
        NSLog(@"XTWebSocket heartbeatAction not login!");
        return;
    }
    switch (self.socket.readyState) {
        case SR_CONNECTING:
            break;
        case SR_OPEN:
            [self sendPing];
            break;
        case SR_CLOSING:
            break;
        case SR_CLOSED:
            [self reConnectSocket];
            break;
    }
}


//重连机制
- (void)reConnectSocket{
    [self closeWebSocket];
    [self initWebSocket];
}


// 关闭Socket
- (void)close {
    [self destoryHeartbeat];
    [self.socket close];
    self.socket = nil;
}

#pragma mark -- SRWebSocketDelegate
//收到服务器消息是回调
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{
    NSLog(@"----XTWebSocket didReceiveMessage：%@",message);
    if ([message isKindOfClass:[NSString class]]) {
        NSString *msg = (NSString *)message;
        NSError *error;
        if([msg isEqual:ping]){
            return;
        }
//        NSLog(@"didReceiveMessage：%@",msg);
        NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
        
        NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
        if (error) {
            NSLog(@"JSON解析错误: %@", error);
        } else {
//            NSLog(@"解析后的字典: %@", jsonDict);
            NSString *code =jsonDict[@"code"];
            if([code isEqualToString:SendCode_MESSAGE]){//收到消息数据
                [self onmessage:jsonDict[@"message"]];
                return;
            }
            if([code isEqualToString:SendCode_READ]){//已读消息
                [self onRead:jsonDict[@"message"]];
                return;
            }
            if([code isEqualToString:SendCode_OTHER_LOGIN]){//账号在其他地方登陆
                NSDictionary *mmsg = jsonDict[@"message"];
                NSString *uuid =mmsg[@"uuid"];
                if([uuid isEqualToString:_UUID]){
                    return;
                }
                else{
                    [self logoutAct];
                }
                return;
            }
            if([code isEqualToString:SendCode_NEW_FRIEND]){//好友申请
                NSLog(@"好友申请----------");
                [[NSNotificationCenter defaultCenter] postNotificationName: nkonAddFriendNote object:nil];
                return;
            }
            if([code isEqualToString:SendCode_GROUP_VALIDATE]){//群申请验证
                [[NSNotificationCenter defaultCenter] postNotificationName: nkonEXGroupdNote object:nil];
                return;
            }
            if([code isEqualToString:SendCode_WEBRTC_result]){//音视频通话结果
                [self onmessage:jsonDict[@"message"]];
                return;
            }
            if([code isEqualToString:SendCode_WEBRTC_CALL]){//音视频通话请求
                [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
                return;
            }
            if([code isEqualToString:SendCode_WEBRTC_CLOSE]){//关闭音视频通话
                [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
                return;
            }
            if([code isEqualToString:SendCode_WEBRTC_BUSY]){//音视频通话忙碌
                [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
                return;
            }
            if([code isEqualToString:SendCode_WEBRTC_xinling]){//webrtc信令交互
                [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
                return;
            }
            if([code isEqualToString:SendCode_deletemsg]){//删除消息
               
                return;
            }
            if([code isEqualToString:SendCode_WEBRTC_DFBUSY]){//对方正在忙
                [WebRTCStore.shareInstance reciveMsg:jsonDict[@"message"]];
                return;
            }
            if([code isEqualToString:SendCode_RECMsg]){//收到消息回执
                
                return;
            }
        }
    }
}

//连接成功
- (void)webSocketDidOpen:(SRWebSocket *)webSocket{
    NSLog(@"-----XTWebSocket DidOpen: %ld", webSocket.readyState);
    switch (webSocket.readyState) {
        case SR_CONNECTING:
            break;
        case SR_OPEN:{
            [self sendReady];
            if (![_heatBeat isValid]) {
                [self destoryHeartbeat];
                [self startHeartbeat];
            }
        }break;
        case SR_CLOSING:
            break;
        case SR_CLOSED:
            break;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(onSocketConnectionStateChanged:)]) {
        [self.delegate onSocketConnectionStateChanged:webSocket.readyState];
    }
}


//连接失败的回调
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error{
    NSLog(@"XTWebSocket didFailWithError %@",error);
    // 1.判断当前网络环境，如果断网了就不要连了，等待网络到来，在发起重连
    // 2.判断调用层是否需要连接，例如用户都没在聊天界面，连接上去浪费流量
    if (self.isReachable) {
        [self reConnectSocket];
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(onSocketConnectionStateChanged:)]) {
        [self.delegate onSocketConnectionStateChanged:webSocket.readyState];
    }
}

//连接断开的回调
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{
    NSLog(@"XTWebSocket Close code %ld reason %@",(long)code,reason);
    if (self.delegate && [self.delegate respondsToSelector:@selector(onSocketConnectionStateChanged:)]) {
        [self.delegate onSocketConnectionStateChanged:webSocket.readyState];
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
    NSString *string = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
    NSLog(@"XTWebSocket Pong:%@", string);
}

#pragma mark - 其他 -
- (void)dealloc {
    NSLog(@"LFC: dealloc: %@", self);
    [self close];
}


#pragma mark -数据处理-

-(void)onmessage:(NSDictionary *)msg{
    NSLog(@"onmessage:%@",msg);
//    NSLog(@"%@",msg[@"chatId"]);
//    NSLog(@"%@",msg[@"fromId"]);
    //NSLog(@"%@",msg[@"content"]);
    
    NSMutableDictionary *mutablemsg = [msg mutableCopy];
    
    
    if([self.userid isEqual:msg[@"fromId"]]){
        [mutablemsg setObject:[NSNumber numberWithBool:YES] forKey:@"mine"];
//        NSLog(@"----------------------11");
        [ChatsStore.shareInstance deleteMineTmpMsg:msg];//删除本地临时消息
    }else{
        if([Friendchat isEqual:msg[@"type"]]){
            [mutablemsg setObject:msg[@"fromId"] forKey:@"chatId"];
        }
    }
    [ChatsStore.shareInstance reciveMsg:mutablemsg];//聊天窗信息
    [ChatListStore.shareInstance reciveMsg:[mutablemsg copy]];//聊天窗列表
    [[NSNotificationCenter defaultCenter] postNotificationName:nkonNewMessageNote object:mutablemsg];
    
    NSString *messageType = msg[@"messageType"];
    if ([messageType isEqualToString:MessageType_event]) {
        [[NSNotificationCenter defaultCenter] postNotificationName:nkonJoinGroupNote object:mutablemsg];
    }

}

//消息已收到回执
-(void)sendRecNote:(NSDictionary *)msg{
    NSDictionary *dic =@{
        @"chatId":msg[@"chatId"],
        @"userId":self.userid,
        @"msgId":msg[@"id"],
        @"type":msg[@"type"]
    };
    NSDictionary *sendInfo = @{
        @"code":SendCode_RECMsg,
        @"message":dic,
    };
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sendInfo options:0 error:&error];
    if (!jsonData) {
        NSLog(@"Got an error: %@", error);
    } else {
        NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
//        NSLog(@"jsonString:%@",jsonString);
        [self sendMsg:jsonString];
    }
}

//收到已读消息
-(void)onRead:(NSDictionary *)dis{
    [ChatsStore.shareInstance updatereadTime:dis];
}


//异地登录
-(void)logoutAct{
    NSLog(@"logoutAct");
    [[LoginStateManager sharedManager] logout];
}


#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(@"XTWebSocket ReachabilityStatusChange: %d", isReachable);
        if (isReachable) {
            [self checkReconnectIfNeed];
        }
    }];
    
    [manager startMonitoring];
}

- (BOOL)isReachable {
    return _isReachable;
}

- (void)checkReconnectIfNeed {
    NSLog(@"XTWebSocket checkReconnectIfNeed readyState: %ld", self.socket.readyState);
    switch (self.socket.readyState) {
        case SR_CONNECTING:
            break;
        case SR_OPEN:
            break;
        case SR_CLOSING:
            break;
        case SR_CLOSED:{
            if (self.isReachable) {
                [self reConnectSocket];
            }
        }break;
    }
}

@end
