//
//  RCWebSocket.m
//  Demo
//
//  Created by 余衡武 on 2024/9/30.
//

#import "RCWebSocket.h"
#import "RCTool.h"
#import "RCWSClient.h"

@interface RCWebSocket ()

/// <url, client> url = host+ip
@property (nonatomic, strong) NSMutableDictionary <NSString *, RCWSClient *> *clients;

@property (nonatomic,  assign) int          success;
@property (nonatomic,  assign) int          fail;
@property (nonatomic,  copy) NSString       *orderType;
@property (nonatomic,  copy) NSMutableArray *urls;
@property (nonatomic,  copy) NSString       *order;
@property (nonatomic,  copy) NSMutableArray *successKeys;
@property (nonatomic,  copy) NSMutableArray *failKeys;
@property (nonatomic,  copy) RCProgress     progress;
@property (nonatomic,  copy) RCComplete     complete;

@property (nonatomic,  copy) NSMutableArray *previewUrls;
@property (nonatomic,  copy) RCPreview      preview;

/// 任务执行队列
@property (nonatomic, strong) NSOperationQueue *operationQueue;
/// 任务超时时间戳
@property (nonatomic, strong) NSString         *operationStamp;

@end

@implementation RCWebSocket

#pragma mark - 单例
static RCWebSocket *shareInstance = nil;
+ (RCWebSocket *)shareInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shareInstance = [[RCWebSocket alloc] init];
    });
    return shareInstance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        // 创建一个 NSOperationQueue，设置最大并发操作数为20
        _operationQueue = [[NSOperationQueue alloc] init];
        _operationQueue.maxConcurrentOperationCount = 20;  // 并发数限制为200
    }
    return self;
}

/**
 1、websocket 重连失败
 */
#pragma mark - 同步操作 发送指令 （order:DPI指令、order2:分辨率指令）
- (void)sendSyscOrder:(NSString *)order order2:(NSString *)order2 toUrls:(NSArray *)urls progress:(RCProgress)progress complete:(RCComplete)complete {
    if (urls.count == 0) {  return; }
    
    // 持久化操作数据
    [self configOrder:order urls:urls progress:progress complete:complete];
    
    // 操作解析
    NSMutableArray *newKeys = [NSMutableArray array];
    for (NSString *url in urls) {
        NSString *key = [RCWebSocket getKeyFromUrl:url];
        [newKeys addObject:key];
    }
    
    NSArray *allKeys = [self.clients allKeys];
    NSMutableArray *oldKeys = [NSMutableArray arrayWithArray:allKeys];
    
    NSMutableArray *existArray = [RCWebSocket intersectionOfArray:newKeys withArray:oldKeys]; // 已存在的连接
    NSMutableArray *addArray   = [RCWebSocket differenceOfArray:newKeys fromArray:oldKeys]; // 新增的连接
    
    // 已存在的连接
    for (NSString *key in existArray) {

        RCWSClient *client = [self.clients objectForKey:key];
        NSString *token = [self getTokenFromUrls:self.urls withKey:key];
        client.currentToken = token;
        client.overtime = [RCOperateManager shareInstance].overtime;
        client.reconnectCount = [RCOperateManager shareInstance].reconnectCount;
        
        // 恢复初始状态
        client.syscSuccess = 0;
        client.syscFail = 0;
        
        // 已存在的连接 已断开连接 需要重新建立连接
        if (client.fl_socketStatus != RCSocketStatusConnected && client.fl_socketStatus != RCSocketStatusReceived) {
            [addArray addObject:key];
            [self removeClientForKey:key];
            continue;;
        }
        
        [client fl_send:order];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [client fl_send:order2];
        });
    }
    
    // 需新增的连接
    [self executeSyscOrderTasks:order order2:order2 array:addArray];

}

// 执行任务
- (void)executeSyscOrderTasks:(NSString *)order order2:(NSString *)order2 array:(NSMutableArray *)array {
    // 取消之前的任务
    [self.operationQueue cancelAllOperations];
    
    // 需新增的连接
    __weak typeof(self) weakSelf = self;
    for (NSString *key in array) {
        // 创建一个任务操作
        NSBlockOperation *operation = nil;
        operation = [NSBlockOperation blockOperationWithBlock:^{
            // 检查任务是否已被取消
            if ([[NSOperationQueue currentQueue] operations].count == 0 || [operation isCancelled]) { return; }
            
            // 耗时任务
            RCWSClient *client = [[RCWSClient alloc] init];
            NSString *token = [self getTokenFromUrls:self.urls withKey:key];
            client.currentToken = token;
            client.overtime = [RCOperateManager shareInstance].overtime;
            client.reconnectCount = [RCOperateManager shareInstance].reconnectCount;
            
            // 恢复初始状态
            client.syscSuccess = 0;
            client.syscFail = 0;
            
            NSString *url = [RCWebSocket getUrlFromKey:key token:token];
            [client fl_open:url connect:^{
                [weakSelf.clients setObject:client forKey:key]; // 连接加入字典
                
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [client fl_send:order];

                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        [client fl_send:order2];
                    });
                });
                
            } receive:^(id message, RCSocketReceiveType type) {
                
                // 预览图推流保活-Ping-Pong 心跳机制
                if (type == RCSocketReceiveTypeForPing) {
                    int index = [self getPreviewIndexInForKey:key];
                    if (index < 0) { return; }
                    [client fl_sendPong:nil];
                    
                } else if (type == RCSocketReceiveTypeForPong) {
                    int index = [self getPreviewIndexInForKey:key];
                    if (index < 0) { return; }
                    [client fl_sendPing:nil];
                    
                } else if ([message isKindOfClass:[NSData class]]) { // 预览图解析
                    // Block 返回结果
                    UIImage *img = [RCTool getPreviewImageWebSocketData:(NSData *)message];
                    int index = [self getPreviewIndexInForKey:key];
                    if (index < 0) { return; }
                    self.preview(key, img);
    //                NSLog(@"预览图 key:%@", key);
                    
                } else if ([message isKindOfClass:[NSMutableString class]] || [message isKindOfClass:[NSString class]]) { // 指令返回结果解析
                    NSDictionary *dataDict = [weakSelf getDataDictFrom:(NSString *)message];
                    NSLog(@"%@", dataDict);
                    
                    NSString *type = [NSString stringWithFormat:@"%@", dataDict[@"type"]];
                    NSInteger code = [dataDict[@"code"] integerValue];
                    BOOL isOrderType = [type isEqualToString:weakSelf.orderType];
                    int index = [weakSelf getIndexInForKey:key];
                    if (index < 0) { return; }
                    
                    if ([type isEqualToString:@"sys_resolution"] || [type isEqualToString:@"sys_dpi"]) {
                        // Block回调
                        [weakSelf refreshSyscBlock:client key:key type:type code:code];
                    } else if (isOrderType) {
                        // Block回调
                        [weakSelf refreshSuccessBlock:code key:key];
                        // 关闭连接
                        [weakSelf closeConnecWithKey:key client:client];
                    }
                }
                
            } failure:^(NSError *error) {
                
                NSString *key = [[client.urlString componentsSeparatedByString:@"&"] firstObject];
                int index = [weakSelf getIndexInForKey:key];
                if (error.code == -9999 && index >= 0) {
                    // Block回调
                    [weakSelf refreshFailBlock:key];
                }
                
                if (error.code == -9999 || error.code == -8888) {
                    [weakSelf removeClientForKey:key]; // 从字典移除连接
                }
            }];
        }];
        
        // 将任务添加到队列中
        [weakSelf.operationQueue addOperation:operation];
    }
}


#pragma mark - 批量操作 发送指令
- (void)sendOperationOrder:(NSString *)order toUrls:(NSArray *)urls progress:(RCProgress)progress complete:(RCComplete)complete {
    if (urls.count == 0) {  return; }

    // 持久化操作数据
    [self configOrder:order urls:urls progress:progress complete:complete];
    
    // 操作解析
    NSMutableArray *newKeys = [NSMutableArray array];
    for (NSString *url in urls) {
        NSString *key = [RCWebSocket getKeyFromUrl:url];
        [newKeys addObject:key];
    }
    
    NSArray *allKeys = [self.clients allKeys];
    NSMutableArray *oldKeys = [NSMutableArray arrayWithArray:allKeys];
    
    NSMutableArray *existArray = [RCWebSocket intersectionOfArray:newKeys withArray:oldKeys]; // 已存在的连接
    NSMutableArray *addArray   = [RCWebSocket differenceOfArray:newKeys fromArray:oldKeys]; // 新增的连接
    
    // 已存在的连接
    for (NSString *key in existArray) {

        RCWSClient *client = [self.clients objectForKey:key];
        NSString *token = [self getTokenFromUrls:self.urls withKey:key];
        client.currentToken = token;
        client.overtime = [RCOperateManager shareInstance].overtime;
        client.reconnectCount = [RCOperateManager shareInstance].reconnectCount;
        
        // 已存在的连接 已断开连接 需要重新建立连接
        if (client.fl_socketStatus != RCSocketStatusConnected && client.fl_socketStatus != RCSocketStatusReceived) {
            [addArray addObject:key];
            [self removeClientForKey:key];
            continue;;
        }
        
        [client fl_send:order];
    }
    
    // 需新增的连接
    [self executeOperationOrderTasks:order array:addArray];
}

// 执行任务
- (void)executeOperationOrderTasks:(NSString *)order array:(NSMutableArray *)array {
    // 取消之前的任务
    [self.operationQueue cancelAllOperations];
    
    // 需新增的连接
    __weak typeof(self) weakSelf = self;
    for (NSString *key in array) {
        // 创建一个任务操作
        NSBlockOperation *operation = nil;
        operation = [NSBlockOperation blockOperationWithBlock:^{
            // 检查任务是否已被取消
            if ([[NSOperationQueue currentQueue] operations].count == 0 || [operation isCancelled]) { return; }
            
            // 耗时任务
            
            RCWSClient *client = [[RCWSClient alloc] init];
            NSString *token = [self getTokenFromUrls:self.urls withKey:key];
            client.currentToken = token;
            client.overtime = [RCOperateManager shareInstance].overtime;
            client.reconnectCount = [RCOperateManager shareInstance].reconnectCount;
            
            NSString *url = [RCWebSocket getUrlFromKey:key token:token];
            [client fl_open:url connect:^{
                [weakSelf.clients setObject:client forKey:key]; // 连接加入字典
                
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [client fl_send:order];
                });
                
            } receive:^(id message, RCSocketReceiveType type) {

                // 预览图推流保活-Ping-Pong 心跳机制
                if (type == RCSocketReceiveTypeForPing) {
                    int index = [self getPreviewIndexInForKey:key];
                    if (index < 0) { return; }
                    [client fl_sendPong:nil];
                    
                } else if (type == RCSocketReceiveTypeForPong) {
                    int index = [self getPreviewIndexInForKey:key];
                    if (index < 0) { return; }
                    [client fl_sendPing:nil];
                    
                } else if ([message isKindOfClass:[NSData class]]) { // 预览图解析
                    // Block 返回结果
                    UIImage *img = [RCTool getPreviewImageWebSocketData:(NSData *)message];
                    int index = [self getPreviewIndexInForKey:key];
                    if (index < 0) { return; }
                    self.preview(key, img);
    //                NSLog(@"预览图 key:%@", key);
                    
                } else if ([message isKindOfClass:[NSMutableString class]] || [message isKindOfClass:[NSString class]]) { // 指令返回结果解析
                    NSDictionary *dataDict = [weakSelf getDataDictFrom:(NSString *)message];
                    NSLog(@"%@", dataDict);
                    
                    NSString *type = [NSString stringWithFormat:@"%@", dataDict[@"type"]];
                    NSInteger code = [dataDict[@"code"] integerValue];
                    BOOL isOrderType = [type isEqualToString:weakSelf.orderType];
                    int index = [weakSelf getIndexInForKey:key];
                    if (index < 0) { return; }
                    
                    if ([type isEqualToString:@"sys_resolution"] || [type isEqualToString:@"sys_dpi"]) {
                        // Block回调
                        [weakSelf refreshSyscBlock:client key:key type:type code:code];
                    } else if (isOrderType) {
                        // Block回调
                        [weakSelf refreshSuccessBlock:code key:key];
                        // 关闭连接
                        [weakSelf closeConnecWithKey:key client:client];
                    }
                }
                
            } failure:^(NSError *error) {
                
                NSString *key = [[client.urlString componentsSeparatedByString:@"&"] firstObject];
                int index = [weakSelf getIndexInForKey:key];
                if (error.code == -9999 && index >= 0) {
                    // Block回调
                    [weakSelf refreshFailBlock:key];
                }
                
                if (error.code == -9999 || error.code == -8888) {
                    [weakSelf removeClientForKey:key]; // 从字典移除连接
                }
            }];
        }];
        
        // 将任务添加到队列中
        [weakSelf.operationQueue addOperation:operation];
    }
}


#pragma mark - 预览图操作 发送指令 （order:关闭预览、order2:开启预览）
- (void)sendPreviewOrder:(NSString *)order order2:(NSString *)order2 toUrls:(NSArray *)urls preview:(RCPreview)preview {
    if (urls.count == 0) { return; }

    // 持久化操作数据
    [self configPreviewOrder:urls preview:preview];
    
    // 操作解析
    NSMutableArray *newKeys = [NSMutableArray array];
    for (NSString *url in urls) {
        NSString *key = [RCWebSocket getKeyFromUrl:url];
        [newKeys addObject:key];
    }
    
    NSArray *allKeys = [self.clients allKeys];
    NSMutableArray *oldKeys = [NSMutableArray arrayWithArray:allKeys];
    
    NSMutableArray *existArray   = [RCWebSocket intersectionOfArray:newKeys withArray:oldKeys]; // 已存在的连接
    NSMutableArray *addArray     = [RCWebSocket differenceOfArray:newKeys fromArray:oldKeys];   // 新增的连接
    NSMutableArray *deleteArray  = [RCWebSocket differenceOfArray:oldKeys fromArray:newKeys];   // 移除的连接
    
    // 需移除的连接
    for (NSString *key in deleteArray) {
        
        RCWSClient *client = [self.clients objectForKey:key];
        client.overtime = [RCOperateManager shareInstance].overtime;
        client.reconnectCount = [RCOperateManager shareInstance].reconnectCount;
        
        [client fl_send:order]; // 停止预览图推流指令
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self closeConnecWithKey:key client:client];
        });
    }
    
    // 已存在的连接
    for (NSString *key in existArray) {

        RCWSClient *client = [self.clients objectForKey:key];
        NSString *token = [self getTokenFromUrls:self.previewUrls withKey:key];
        client.currentToken = token;
        client.overtime = [RCOperateManager shareInstance].overtime;
        client.reconnectCount = [RCOperateManager shareInstance].reconnectCount;
        
        // 已存在的连接 已断开连接 需要重新建立连接
        if (client.fl_socketStatus != RCSocketStatusConnected && client.fl_socketStatus != RCSocketStatusReceived) {
            [addArray addObject:key];
            [self removeClientForKey:key];
            continue;;
        }
        
        [client fl_send:order];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [client fl_send:order2];
        });
        
        __weak typeof(client) weakClient = client;
        client.receive = ^(id message, RCSocketReceiveType type) {
            
            // 预览图推流保活-Ping-Pong 心跳机制
            if (type == RCSocketReceiveTypeForPing) {
                int index = [self getPreviewIndexInForKey:key];
                if (index < 0) { return; }
                [weakClient fl_sendPong:nil];
                
            } else if (type == RCSocketReceiveTypeForPong) {
                int index = [self getPreviewIndexInForKey:key];
                if (index < 0) { return; }
                [weakClient fl_sendPing:nil];
                
            } else if ([message isKindOfClass:[NSData class]]) { // 预览图解析
                // Block 返回结果
                UIImage *img = [RCTool getPreviewImageWebSocketData:(NSData *)message];
                int index = [self getPreviewIndexInForKey:key];
                if (index < 0) { return; }
                self.preview(key, img);
//                NSLog(@"预览图 key:%@", key);
                
            } else if ([message isKindOfClass:[NSMutableString class]] || [message isKindOfClass:[NSString class]]) {  // 指令返回结果解析
                NSDictionary *dataDict = [self getDataDictFrom:(NSString *)message];
                NSLog(@"%@", dataDict);
                
                NSString *type = [NSString stringWithFormat:@"%@", dataDict[@"type"]];
                NSInteger code = [dataDict[@"code"] integerValue];
                BOOL isOrderType = [type isEqualToString:self.orderType];
                int index = [self getIndexInForKey:key];
                if (index < 0) { return; }
                
                if ([type isEqualToString:@"sys_resolution"] || [type isEqualToString:@"sys_dpi"]) {
                    // Block回调
                    [self refreshSyscBlock:weakClient key:key type:type code:code];
                } else if (isOrderType) {
                    // Block回调
                    [self refreshSuccessBlock:code key:key];
                    // 关闭连接
                    [self closeConnecWithKey:key client:weakClient];
                }
            }
        };
        
        client.failure = ^(NSError *error) {
            
            NSString *key = [[weakClient.urlString componentsSeparatedByString:@"&"] firstObject];
            int index = [self getIndexInForKey:key];
            if (error.code == -9999 && index >= 0) {
                // Block回调
                [self refreshFailBlock:key];
            }
            
            if (error.code == -9999 || error.code == -8888) {
                [self removeClientForKey:key]; // 从字典移除连接
            }
        };
    }
    
    // 需新增的连接
    for (NSString *key in addArray) {
        
        RCWSClient *client = [[RCWSClient alloc] init];
        NSString *currentToken = [self getTokenFromUrls:urls withKey:key];
        client.currentToken = currentToken;
        client.overtime = [RCOperateManager shareInstance].overtime;
        client.reconnectCount = [RCOperateManager shareInstance].reconnectCount;
        NSString *url = [RCWebSocket getUrlFromKey:key token:currentToken];
        
        __weak typeof(client) weakClient = client;
        [client fl_open:url connect:^{
            [self.clients setObject:client forKey:key]; // 连接加入字典
            
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [client fl_send:order];

                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [client fl_send:order2];
                });
            });
            
        } receive:^(id message, RCSocketReceiveType type) {
            
            // 预览图推流保活-Ping-Pong 心跳机制
            if (type == RCSocketReceiveTypeForPing) {
                int index = [self getPreviewIndexInForKey:key];
                if (index < 0) { return; }
                [client fl_sendPong:nil];
                
            } else if (type == RCSocketReceiveTypeForPong) {
                int index = [self getPreviewIndexInForKey:key];
                if (index < 0) { return; }
                [client fl_sendPing:nil];
                
            } else if ([message isKindOfClass:[NSData class]]) { // 预览图解析
                // Block 返回结果 正常
                UIImage *img = [RCTool getPreviewImageWebSocketData:(NSData *)message];
                int index = [self getPreviewIndexInForKey:key];
                if (index < 0) { return; } // 无用数据
                self.preview(key, img);
//                NSLog(@"预览图 key:%@", key);
                
            } else if ([message isKindOfClass:[NSMutableString class]] || [message isKindOfClass:[NSString class]]) {  // 指令返回结果解析
                NSDictionary *dataDict = [self getDataDictFrom:(NSString *)message];
                NSLog(@"%@", dataDict);
                
                NSString *type = [NSString stringWithFormat:@"%@", dataDict[@"type"]];
                NSInteger code = [dataDict[@"code"] integerValue];
                BOOL isOrderType = [type isEqualToString:self.orderType];
                int index = [self getIndexInForKey:key];
                if (index < 0) { return; }
                
                if ([type isEqualToString:@"sys_resolution"] || [type isEqualToString:@"sys_dpi"]) {
                    // Block回调
                    [self refreshSyscBlock:weakClient key:key type:type code:code];
                } else if (isOrderType) {
                    // Block回调
                    [self refreshSuccessBlock:code key:key];
                    // 关闭连接
                    [self closeConnecWithKey:key client:weakClient];
                }
            }
            
        } failure:^(NSError *error) {
            
            NSString *key = [[client.urlString componentsSeparatedByString:@"&"] firstObject];
            int index = [self getIndexInForKey:key];
            if (error.code == -9999 && index >= 0) {
                // Block回调
                [self refreshFailBlock:key];
            }
            
            if (error.code == -9999 || error.code == -8888) {
                [self removeClientForKey:key]; // 从字典移除连接
            }
        }];
    }
}

#pragma mark - 停止所有预览图推流
- (void)stopAllConnect {
    NSString *order  = [RCWSOrder stopPreview];
    NSArray *allKeys = [self.clients allKeys];
    NSMutableArray *oldKeys = [NSMutableArray arrayWithArray:allKeys];
    
    // 移除所有连接
    for (NSString *key in oldKeys) {
        
        RCWSClient *client = [self.clients objectForKey:key];
        client.overtime = [RCOperateManager shareInstance].overtime;
        client.reconnectCount = [RCOperateManager shareInstance].reconnectCount;
        
        [client fl_send:order]; // 停止预览图推流指令
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [client fl_close:^(NSInteger code, NSString *reason, BOOL wasClean) {
                NSLog(@"关闭websocket连接 成功 stopAllConnect");
            }];
            
            [self removeClientForKey:key];
        });
    }
}

/// 关闭连接
- (void)closeConnecWithKey:(NSString *)key client:(RCWSClient *)client  {
    int index = [self getPreviewIndexInForKey:key];
    if (index >= 0) { return; }
    
    [client fl_close:^(NSInteger code, NSString *reason, BOOL wasClean) {
        NSLog(@"关闭websocket连接 成功 closeConnecWithKey");
    }];
    
    [self removeClientForKey:key];
}

/// 从字典里删除连接
- (void)removeClientForKey:(NSString *)key {
    if ([[self.clients allKeys] containsObject:key]) {
        [self.clients removeObjectForKey:key]; // 从字典移除连接
    }
}

#pragma mark - 辅助方法
/// 取交集
+ (NSMutableArray *)intersectionOfArray:(NSArray *)array1 withArray:(NSArray *)array2 {
    // 检查数组是否为空
    if (array1.count == 0 || array2.count == 0) {
        return [NSMutableArray array]; // 返回空数组
    }
    
    NSSet *set1 = [NSSet setWithArray:array1];
    NSSet *set2 = [NSSet setWithArray:array2];
    
    NSMutableSet *intersectionSet = [NSMutableSet setWithSet:set1];
    [intersectionSet intersectSet:set2];
    
    NSArray *array = [intersectionSet allObjects];
    return [NSMutableArray arrayWithArray:array];
}

// 取差集
+ (NSMutableArray *)differenceOfArray:(NSArray *)array1 fromArray:(NSArray *)array2 {
    // 检查数组是否为空
    if (array1.count == 0) {
        return [NSMutableArray array];
    } else if (array2.count == 0) {
        return [NSMutableArray arrayWithArray:array1];;
    }
    
    NSSet *set1 = [NSSet setWithArray:array1];
    NSSet *set2 = [NSSet setWithArray:array2];
    
    NSMutableSet *differenceSet = [NSMutableSet setWithSet:set1];
    [differenceSet minusSet:set2];
    
    NSArray *array = [differenceSet allObjects];
    return [NSMutableArray arrayWithArray:array];
}

+ (NSString *)getKeyFromUrl:(NSString *)url {
    NSArray *array = [url componentsSeparatedByString:@"&"];
    return array.firstObject;
}

+ (NSString *)getUrlFromKey:(NSString *)key token:(NSString *)token {
    NSString *deviceID = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    return [NSString stringWithFormat:@"%@&Device-ID=%@&%@", key, deviceID, token];
}

+ (NSString *)getTokenFromUrl:(NSString *)url {
    NSArray *array = [url componentsSeparatedByString:@"&"];
    return array.lastObject;
}

- (NSString *)getTokenFromUrls:(NSArray<NSString *> *)array withKey:(NSString *)key {
    NSString *targetIP = [self extractQueryParam:@"ip" fromURLString:key];
    if (!targetIP) return nil;

    for (NSString *urlString in array) {
        NSString *currentIP = [self extractQueryParam:@"ip" fromURLString:urlString];
        if (![currentIP isEqualToString:targetIP]) continue;

        NSString *authValue = [self extractRawQueryParam:@"Authorization" fromURLString:urlString];
        if (authValue) {
            return [NSString stringWithFormat:@"Authorization=%@", authValue];
        }
    }
    return nil;
}

- (NSString *)extractQueryParam:(NSString *)param fromURLString:(NSString *)urlString {
    NSURLComponents *components = [NSURLComponents componentsWithString:urlString];
    for (NSURLQueryItem *item in components.queryItems) {
        if ([item.name isEqualToString:param]) {
            return item.value;
        }
    }
    return nil;
}

- (NSString *)extractRawQueryParam:(NSString *)param fromURLString:(NSString *)urlString {
    NSRange queryRange = [urlString rangeOfString:@"?"];
    if (queryRange.location == NSNotFound) return nil;

    NSString *queryString = [urlString substringFromIndex:queryRange.location + 1];
    NSArray<NSString *> *params = [queryString componentsSeparatedByString:@"&"];
    for (NSString *pair in params) {
        NSArray<NSString *> *keyValue = [pair componentsSeparatedByString:@"="];
        if (keyValue.count != 2) continue;
        if ([keyValue[0] isEqualToString:param]) {
            return keyValue[1]; // 返回未解码的值
        }
    }
    return nil;
}


#pragma mark - 同步操作
- (void)refreshSyscBlock:(RCWSClient *)client key:(NSString *)key type:(NSString *)type code:(NSInteger)code {
    if (![type isEqualToString:@"sys_resolution"] && ![type isEqualToString:@"sys_dpi"]) {
        return;
    }
    
    if (code == 0) {
        client.syscSuccess += 1;
    } else {
        client.syscFail += 1;
    }
    
    BOOL isSuccess = client.syscSuccess == 2;
    BOOL isComplete = client.syscFail + client.syscSuccess == 2;
    if (isSuccess) { // 已结束-成功
        // Block回调
        [self refreshSuccessBlock:0 key:key];
        // 关闭连接
        [self closeConnecWithKey:key client:client];
    } else if (isComplete) { // 已结束-失败
        // Block回调
        [self refreshSuccessBlock:1 key:key];
        // 关闭连接
        [self closeConnecWithKey:key client:client];
    } else {
        NSLog(@"同步指令 执行中");
    }
}


#pragma mark - 批量操作
/// 记录Block等任务信息
- (void)configOrder:(NSString *)order urls:(NSArray *)urls progress:(RCProgress)progress complete:(RCComplete)complete {
    NSString *timeStamp = [RCTool timeStamp];
    self.operationStamp = timeStamp;
    
    self.success   = 0;
    self.fail      = 0;
    
    self.urls      = [NSMutableArray arrayWithArray:urls];
    self.order     = order;
    self.orderType = [RCWSOrder getTypeFromOrder:order];
    
    self.progress  = progress;
    self.complete  = complete;
    
    [self.failKeys removeAllObjects];
    [self.successKeys removeAllObjects];
    
    /// 超时失败
    NSUInteger timeout = [[RCOperateManager shareInstance] timeout];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (![self.operationStamp isEqualToString:timeStamp]) { return; }
        [self refreshTimeoutBlock];
    });
}

/// 成功Block 回调
- (void)refreshSuccessBlock:(NSInteger)code key:(NSString *)key {
    if (code == 0) {
        self.success += 1;
        [self.successKeys addObject:key];
    } else {
        self.fail += 1;
        [self.failKeys addObject:key];
    }
    
    if (self.success + self.fail < self.urls.count) {
        self.progress(self.success, self.fail);
    } else if (self.success + self.fail == self.urls.count) {
        self.progress(self.success, self.fail);
        self.complete(YES);
    }
}

/// 失败Block回调
- (void)refreshFailBlock:(NSString *)key {
    // 防止失败回调重复计算
    if ([self.failKeys containsObject:key]) { return; }
    if ([self.successKeys containsObject:key]) { return; }
    
    self.fail += 1;
    [self.failKeys addObject:key];
    
    // Block回调
    if (self.success + self.fail < self.urls.count) {
        self.progress(self.success, self.fail);
    } else if (self.success + self.fail == self.urls.count) {
        self.progress(self.success, self.fail);
        self.complete(YES);
    }
}

/// 超时Block回调
- (void)refreshTimeoutBlock {
    if (self.success + self.fail < self.urls.count) {
        self.fail = (int)self.urls.count - self.success;
        self.progress(self.success, self.fail);
        self.complete(YES);
    }
}

- (int)getIndexInForKey:(NSString *)key {
    NSMutableArray *newKeys = [NSMutableArray array];
    for (NSString *url in self.urls) {
        NSString *key = [RCWebSocket getKeyFromUrl:url];
        [newKeys addObject:key];
    }
    NSUInteger index = [newKeys indexOfObject:key];
    return (int)index;
}


#pragma mark - 预览图
/// 记录Block等任务信息
- (void)configPreviewOrder:(NSArray *)urls preview:(RCPreview)preview {
    self.previewUrls  = [NSMutableArray arrayWithArray:urls];
    self.preview      = preview;
}

/// 解析接收到的指令数据
- (NSDictionary *)getDataDictFrom:(NSString *)json {
    NSData *message = [json dataUsingEncoding:(NSUTF8StringEncoding)];
    NSDictionary *dataDict = [NSJSONSerialization JSONObjectWithData:message options:NSJSONReadingMutableContainers error:nil];
    return dataDict;
}

- (int)getPreviewIndexInForKey:(NSString *)key {
    NSMutableArray *newKeys = [NSMutableArray array];
    for (NSString *url in self.previewUrls) {
        NSString *key = [RCWebSocket getKeyFromUrl:url];
        [newKeys addObject:key];
    }
    NSUInteger index = [newKeys indexOfObject:key];
    return (int)index;
}

#pragma mark - 懒加载
- (NSMutableDictionary<NSString *,RCWSClient *> *)clients {
    if (!_clients) {
        _clients = [[NSMutableDictionary alloc] init];
    }
    return _clients;
}

- (NSMutableArray *)failKeys {
    if (!_failKeys) {
        _failKeys = [NSMutableArray array];
    }
    return _failKeys;
}

- (NSMutableArray *)successKeys {
    if (!_successKeys) {
        _successKeys = [NSMutableArray array];
    }
    return _successKeys;
}

@end
