//
//  ZYJQNHttpResponseInfo.m
//  ZYJQiniuSDK
//
//  Created by WorkSpace_Sun on 2020/4/19.
//  Copyright © 2020 Qiniu. All rights reserved.
//

#import "ZYJQNHttpResponseInfo.h"
#import "ZYJQNSystemTool.h"
#import "ZYJQNUploadInfoCollector.h"
#import "ZYJQNUserAgent.h"
#import "ZYJQNVersion.h"
#import "ZYJQNSessionManager.h"

@interface ZYJQNHttpResponseInfo ()
@property (nonatomic, strong) NSDictionary *responseBody;
@end

@implementation ZYJQNHttpResponseInfo
+ (ZYJQNHttpResponseInfo *)buildResponseInfoHost:(NSString *)host
                                     response:(NSHTTPURLResponse *)response
                                         body:(NSData *)body
                                        error:(NSError *)error
                            sessionStatistics:(ZYJQNSessionStatistics *)sessionStatistics {
    return [[[self class] alloc] initWithResponseInfoHost:host response:response body:body error:error sessionStatistics:sessionStatistics];
}

- (instancetype)initWithResponseInfoHost:(NSString *)host
                                response:(NSHTTPURLResponse *)response
                                    body:(NSData *)body
                                   error:(NSError *)error
                       sessionStatistics:(ZYJQNSessionStatistics *)sessionStatistics {
    
    self = [super init];
    if (self) {
        
        _statusCode = ZYJQN_IntNotSet;
        _signalStrength = ZYJQN_IntNotSet;
        _proxyConnection = NO;
        _hasHttpResponse = NO;
        _host = host;
        _pid = [ZYJQNSystemTool getCurrentProcessID];
        _tid = [ZYJQNSystemTool getCurrentThreadID];
        _timeStamp = [[NSDate date] timeIntervalSince1970];
        
        _bytesSent = sessionStatistics.bytesSent;
        _bytesTotal = sessionStatistics.bytesTotal;
        _remoteIp = sessionStatistics.remoteIp;
        _port = sessionStatistics.port;
        _totalElapsedTime = sessionStatistics.totalElapsedTime;
        _dnsElapsedTime = sessionStatistics.dnsElapsedTime;
        _connectElapsedTime = sessionStatistics.connectElapsedTime;
        _tlsConnectElapsedTime = sessionStatistics.tlsConnectElapsedTime;
        _requestElapsedTime = sessionStatistics.requestElapsedTime;
        _waitElapsedTime = sessionStatistics.waitElapsedTime;
        _responseElapsedTime = sessionStatistics.responseElapsedTime;
        _proxyConnection = sessionStatistics.isProxyConnection;
        
        if (response) {
            _hasHttpResponse = YES;
            int statusCode = (int)[response statusCode];
            NSDictionary *headers = [response allHeaderFields];
            _statusCode = statusCode;
            _reqId = headers[@"X-Reqid"];
            _xlog = headers[@"X-Log"];
            _xvia = !headers[@"X-Via"] ? (!headers[@"X-Px"] ? headers[@"Fw-Via"] : headers[@"X-Px"]) : headers[@"X-Via"];

            if (statusCode != 200) {
                if (response.statusCode / 100 == 4) {
                    _errorType = ZYJbad_request;
                }  else {
                    _errorType = ZYJresponse_error;
                }
                
                if (body == nil) {
                    _error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:nil];
                } else {
                    NSError *tmp;
                    NSDictionary *uInfo = [NSJSONSerialization JSONObjectWithData:body options:NSJSONReadingMutableLeaves error:&tmp];
                    if (tmp != nil) {
                        // 出现错误时，如果信息是非UTF8编码会失败，返回nil
                        NSString *str = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
                        if (str == nil) {
                            str = @"";
                        }
                        uInfo = @{ @"error" : str };
                    }
                    _error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:uInfo];
                }
            } else if (body == nil || body.length == 0) {
                NSDictionary *uInfo = @{ @"error" : @"no response json" };
                _errorType = ZYJunknown_error;
                _error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:uInfo];
            } else {
                NSError *tmp;
                NSDictionary *responseBody = [NSJSONSerialization JSONObjectWithData:body options:NSJSONReadingMutableLeaves error:&tmp];
                if (!error) {
                    _responseBody = responseBody;
                } else {
                    NSDictionary *uInfo = @{ @"error" : @"JSON serialization failed" };
                    _errorType = ZYJparse_error;
                    _error = [[NSError alloc] initWithDomain:host code:statusCode userInfo:uInfo];
                }
            }
        } else {
            _hasHttpResponse = NO;
            if (error) {
                _error = error;
                _statusCode = (int)error.code;
                _errorDescription = _error.localizedDescription;
                
                if (self.isProxyConnection) {
                    _errorType = ZYJproxy_error;
                } else {
                    if (error.code == -1 || error.code == -1009) {
                        _errorType = ZYJnetwork_error;
                    } else if (error.code == -1001) {
                        _errorType = ZYJnetwork_timeout;
                    } else if (error.code == -1003 || error.code == -1006) {
                        _errorType = ZYJunknown_host;
                    } else if (error.code == -1004) {
                        _errorType = ZYJcannot_connect_to_host;
                    } else if (error.code == -1005 || error.code == -1011) {
                        _errorType = ZYJtransmission_error;
                    } else if (error.code > -2001 && error.code < -1199) {
                        _errorType = ZYJssl_error;
                    } else if (error.code == -1007 || error.code == -1010) {
                        _errorType = ZYJmalicious_response;
                    } else if (error.code == -1015 || error.code == -1016 || error.code == -1017) {
                        _errorType = ZYJparse_error;
                    } else if (error.code == -999) {
                        _errorType = ZYJuser_canceled;
                    } else if (error.code == 100) {
                        _errorType = ZYJprotocol_error;
                    } else {
                        _errorType = ZYJunknown_error;
                    }
                }
            }
        }
    }
    return self;
}

- (BOOL)isOK {
    return _statusCode == 200 && _error == nil && _reqId != nil;
}

- (BOOL)couldRetry {
    return (_statusCode >= 500 && _statusCode < 600 && _statusCode != 579) || _statusCode == 996 || _statusCode == 406 || (_statusCode == 200 && _error != nil) || _statusCode < -1000 || self.isNotQiniu;
}

- (BOOL)isNotQiniu {
    return (_statusCode >= 200 && _statusCode < 500) && _reqId == nil;
}

- (NSDictionary *)getResponseBody {
    return self.isOK ? self.responseBody : nil;
}

- (int64_t)getTimeintervalWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate {
    
    if (!startDate || !endDate) return 0;
    NSTimeInterval interval = [endDate timeIntervalSinceDate:startDate];
    return interval * 1000;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"<%@= id: %@, ver: %@, status: %lld, requestId: %@, xlog: %@, xvia: %@, host: %@ duration: %.3f s time: %llu error: %@>", NSStringFromClass([self class]), [ZYJQNUserAgent sharedInstance].id, kQiniuVersion, _statusCode, _reqId, _xlog, _xvia, _host, _totalElapsedTime / 1000.0, _timeStamp, _error];
}

@end
