//
//  RCWSClient.m
//  Demo
//
//  Created by 余衡武 on 2024/10/10.
//

#import "RCWSClient.h"

/*
 * author 孔凡列
 *
 * gitHub https://github.com/gitkong
 * cocoaChina http://code.cocoachina.com/user/
 * 简书 http://www.jianshu.com/users/fe5700cfb223/latest_articles
 * QQ 279761135
 * 喜欢就给个like 和 star 喔~
 */

#import "RCWSClient.h"
#import "SRWebSocket.h"

@interface RCWSClient ()<SRWebSocketDelegate>
@property (nonatomic,strong)SRWebSocket *webSocket;

@property (nonatomic,assign)RCSocketStatus fl_socketStatus;

@property (nonatomic,weak)NSTimer *timer;

@property (nonatomic,copy)NSString *urlString;

@end

@implementation RCWSClient{
    NSInteger _reconnectCounter;
}

// 正常的初始化方法
- (instancetype)init {
    self = [super init];
    if (self) {
        self.overtime = 1;
        self.reconnectCount = 5;
        self.syscSuccess = 0;
        self.syscFail = 0;
    }
    return self;
}

- (void)fl_open:(NSString *)urlStr connect:(RCSocketDidConnectBlock)connect receive:(RCSocketDidReceiveBlock)receive failure:(RCSocketDidFailBlock)failure{
    self.connect = connect;
    self.receive = receive;
    self.failure = failure;
    [self fl_open:urlStr];
}

- (void)fl_close:(RCSocketDidCloseBlock)close{
    self.close = close;
    [self fl_close];
}

// Send a UTF8 String or Data.
- (void)fl_send:(id)data{
    switch (self.fl_socketStatus) {
        case RCSocketStatusConnected:
        case RCSocketStatusReceived:{
            NSLog(@"发送中。。。\n %@", data);
            [self.webSocket send:data];
            break;
        }
        case RCSocketStatusFailed:
            NSLog(@"发送失败");
            break;
        case RCSocketStatusClosedByServer:
            NSLog(@"已经关闭");
            break;
        case RCSocketStatusClosedByUser:
            NSLog(@"已经关闭");
            break;
    }
    
}

// Send a UTF8 String or Data.
- (void)fl_sendPong:(id)data{
    switch (self.fl_socketStatus) {
        case RCSocketStatusConnected:
        case RCSocketStatusReceived:{
            NSLog(@"Pong 发送中。。。");
            [self.webSocket sendPong:data];
            break;
        }
        case RCSocketStatusFailed:
            NSLog(@"Pong 发送失败");
            break;
        case RCSocketStatusClosedByServer:
            NSLog(@"Pong 已经关闭");
            break;
        case RCSocketStatusClosedByUser:
            NSLog(@"Pong 已经关闭");
            break;
    }
    
}

// Send a UTF8 String or Data.
- (void)fl_sendPing:(id)data{
    switch (self.fl_socketStatus) {
        case RCSocketStatusConnected:
        case RCSocketStatusReceived:{
            NSLog(@"Ping 发送中。。。");
            [self.webSocket sendPing:data];
            break;
        }
        case RCSocketStatusFailed:
            NSLog(@"Ping 发送失败");
            break;
        case RCSocketStatusClosedByServer:
            NSLog(@"Ping 已经关闭");
            break;
        case RCSocketStatusClosedByUser:
            NSLog(@"Ping 已经关闭");
            break;
    }
    
}

#pragma mark -- private method
- (void)fl_open:(id)params{
//    NSLog(@"params = %@",params);
    NSString *urlStr = nil;
    if ([params isKindOfClass:[NSString class]]) {
        urlStr = (NSString *)params;
    }
    else if([params isKindOfClass:[NSTimer class]]) {
        NSTimer *timer = (NSTimer *)params;
        urlStr = [timer userInfo];
    }
    self.urlString = urlStr;
    [self.webSocket close];
    self.webSocket.delegate = nil;
    
    self.webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]]];
    self.webSocket.delegate = self;
    
    [self.webSocket open];
}

- (void)fl_close{
    
    [self.webSocket close];
    self.webSocket = nil;
    [self.timer invalidate];
    self.timer = nil;
}

- (void)fl_reconnect{
    NSString *token = [[self.urlString componentsSeparatedByString:@"&"] lastObject];
    if (![self.currentToken isEqualToString:token]) { // 控制token已改变 无需重连
        NSLog(@"%@ Websocket Reconnected Cancel ：控制token已改变 无需重连", [self getCurrentTime]);
        NSError *error = [NSError errorWithDomain:@"Websocket Reconnected Outnumber ReconnectCount -8888" code:-8888 userInfo:nil];
        self.failure(error);
        
        if (self.timer) {
            [self.timer invalidate];
            self.timer = nil;
        }
        return;
    } else if (_reconnectCounter < self.reconnectCount - 1) { // 计数+1
        _reconnectCounter ++;
        // 开启定时器
        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:self.overtime target:self selector:@selector(fl_open:) userInfo:self.urlString repeats:NO];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        self.timer = timer;
    } else {
        NSLog(@"%@ Websocket Reconnected Outnumber ReconnectCount ：%@", [self getCurrentTime], _urlString);
        NSError *error = [NSError errorWithDomain:@"Websocket Reconnected Outnumber ReconnectCount -9999" code:-9999 userInfo:nil];
        self.failure(error);
        
        if (self.timer) {
            [self.timer invalidate];
            self.timer = nil;
        }
        return;
    }
    
}

- (NSString *)getCurrentTime {
    NSDate *currentDate = [NSDate date];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *dateString = [dateFormatter stringFromDate:currentDate];
    return dateString;
}

#pragma mark -- SRWebSocketDelegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket{
    NSLog(@"RCWSClient Websocket Connected");
    
    self.connect ? self.connect() : nil;
    self.fl_socketStatus = RCSocketStatusConnected;
    // 开启成功后重置重连计数器
    _reconnectCounter = 0;
}

- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error{
    NSLog(@"RCWSClient Websocket Failed With Error %@", error);
    self.fl_socketStatus = RCSocketStatusFailed;
    self.failure ? self.failure(error) : nil;
    // 重连
    [self fl_reconnect];
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{
//    NSLog(@":( Websocket Receive With message %@", message);
    self.fl_socketStatus = RCSocketStatusReceived;
    self.receive ? self.receive(message,RCSocketReceiveTypeForMessage) : nil;
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{
    NSLog(@"RCWSClient Websocket Closed Reason:%@  code = %zd",reason,code);
    if (reason) {
        self.fl_socketStatus = RCSocketStatusClosedByServer;
        // 重连
        [self fl_reconnect];
    } else {
        self.fl_socketStatus = RCSocketStatusClosedByUser;
    }
    self.close ? self.close(code,reason,wasClean) : nil;
    if (self.closeCallBack) { self.closeCallBack(code,reason,wasClean); }
    self.webSocket = nil;
}

- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload{
    self.receive ? self.receive(pongPayload,RCSocketReceiveTypeForPong) : nil;
}

- (void)webSocket:(SRWebSocket *)webSocket didReceivePing:(NSData *)pongPayload{
    self.receive ? self.receive(pongPayload,RCSocketReceiveTypeForPing) : nil;
}

- (void)dealloc{
    // Close WebSocket
    [self fl_close];
}

@end
