//
//  HWOcrClientAKSKSign.m
//  OCR
//
//  Created by huawei on 2018/10/31.
//  Copyright © 2018/10/31 huawei. All rights reserved.
//

#import "HWOcrClientAKSKSign.h"
#import "HWOcrClientUtils.h"
#import <CommonCrypto/CommonHMAC.h>
#import <CommonCrypto/CommonDigest.h>

@interface HWOcrClientAKSKSign()
// ak
@property (nonatomic, copy)NSString *appKey;
// sk
@property (nonatomic, copy)NSString *appSecretKey;

@property (nonatomic, copy)NSString *algorithm;
@property (nonatomic, copy)NSString *headerXDate;
@property (nonatomic, copy)NSString *headerHost;
@property (nonatomic, copy)NSString *headerAuthorization;
@property (nonatomic, copy)NSString *headerContentSha256;
@end
@implementation HWOcrClientAKSKSign
static HWOcrClientAKSKSign * instance = nil;
+ (instancetype)shardService{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        instance = [[HWOcrClientAKSKSign alloc] init] ;
    }) ;
    return instance ;
}
- (NSString *)SHA256WithString:(NSString *)string
{
    const char *s = [string cStringUsingEncoding:NSASCIIStringEncoding];
    NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
    
    uint8_t digest[CC_SHA256_DIGEST_LENGTH] = {0};
    CC_SHA256(keyData.bytes, (CC_LONG)keyData.length, digest);
    NSData *out = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
    NSString *hexStr = [self hexStringFromData:out];
    return hexStr;
}

- (NSString *)hexStringFromData:(NSData *)data {
    Byte *bytes = (Byte *)[data bytes];
    //Bytes are converted into hexadecimal values as follows
    NSString *hexStr=@"";
    for(int i=0;i<[data length];i++)
    {
        NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];//hex
        if([newHexStr length]==1)
            hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];
        else
            hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr];
    }
    return hexStr;
}

- (NSString *)hmac:(NSString *)plaintext withKey:(NSString *)key
{
    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
    const unsigned char *buffer = (const unsigned char *)[HMACData bytes];
    NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2];
    for (int i = 0; i < HMACData.length; ++i){
        [HMAC appendFormat:@"%02x", buffer[i]];
    }
    return HMAC;
}

- (NSString *)getCurrentTimeFormatter{
    NSDateFormatter *dataFormatter = [[NSDateFormatter alloc] init];
    [dataFormatter setDateFormat:@"yyyyMMdd'T'HHmmss'Z"];
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    [dataFormatter setTimeZone:timeZone];
    NSDate *currentDate = [NSDate date];
    NSString *string = [dataFormatter stringFromDate:currentDate];
    return string;
}
- (void)signWithOcrHttpRequest:(OcrAkSKSignRequest *)r appKey:(NSString *)ak appSecretKey:(NSString *)sk{
    if ([HWOcrClientUtils isBlankString:ak]) {
        NSLog(@"appKey cannot be empty");
        return;
    }
    if ([HWOcrClientUtils isBlankString:sk]) {
        NSLog(@"appSecretKey cannot be empty");
        return;
    }
    self.algorithm = @"SDK-HMAC-SHA256";
    self.headerXDate = @"X-Sdk-Date";
    self.headerHost = @"host";
    self.headerAuthorization = @"Authorization";
    self.headerContentSha256 = @"x-sdk-content-sha256";
    self.appKey = ak;
    self.appSecretKey = sk;
    
    [r.headers addEntriesFromDictionary:@{self.headerXDate:[self getCurrentTimeFormatter], @"host":r.host}];
    NSString *canonicalRequest = [self canonicalRequest:r];
    NSString *stringToSign = [self stringToSign:canonicalRequest currentTime:r.headers[@"x-sdk-date"]];
    NSString *signature = [self signStringToSign:stringToSign SigningKey:self.appSecretKey];
    NSString *signedHeaders = [self signedHeaders:r];
    NSString *authValue = [self authHeaderValueWithSignature:signature AppKey:self.appKey SignedHeaders:signedHeaders];
    NSString *queryString = [self canonicalQueryString:r];
    
    if (queryString.length > 0) {
        r.uri = [NSString stringWithFormat:@"%@?%@", r.uri, queryString];
    }
    [r.headers addEntriesFromDictionary:@{@"Authorization":authValue}];
    [r.headers addEntriesFromDictionary:@{@"content-length": [NSString stringWithFormat:@"%lu",(unsigned long)r.body.length]}];
}
- (NSString *)canonicalRequest:(OcrAkSKSignRequest *)request{
    NSString *hexencode;
    if ([request.headers.allKeys containsObject:self.headerContentSha256]) {
        hexencode  = request.headers[self.headerContentSha256];
    }else{
        hexencode = [self SHA256WithString:request.body];
    }
    NSString *returnStr = [NSString stringWithFormat:@"%@\n%@\n%@\n%@\n%@\n%@",request.method,[self canonicalURI:request],[self canonicalQueryString:request],[self canonicalHeaders:request],[self signedHeaders:request],hexencode];
    return returnStr;
}
- (NSString *)signStringToSign:(NSString *)stringToSign SigningKey:(NSString *)signingKey{
    return [self hmac:stringToSign withKey:signingKey];
}
- (NSString *)stringToSign:(NSString *)canonicalRequest currentTime:(NSString *)time{
    NSString *str = [NSString stringWithFormat:@"%@\n%@\n%@", self.algorithm, time, [self SHA256WithString:canonicalRequest]];
    return str;
}
- (NSString *)canonicalURI:(OcrAkSKSignRequest *)request{
    NSString *uri = [request.uri stringByRemovingPercentEncoding];
    NSArray *array = [uri componentsSeparatedByString:@"/"];
    NSMutableArray *uriArr = [NSMutableArray array];
    for (NSString *v in array) {
        [uriArr addObject:[v stringByRemovingPercentEncoding]];
    }
    NSString *urlPath = [array componentsJoinedByString:@"/"];
    NSString *lastStr = [urlPath  substringFromIndex:[urlPath length]-1];
    if (![lastStr isEqualToString:@"/"]) {
        urlPath = [NSString stringWithFormat:@"%@/",urlPath];
    }
    return urlPath;
}
- (NSString *)canonicalQueryString:(OcrAkSKSignRequest *)request{
    NSMutableArray *array = [NSMutableArray array];
    for (NSString *key in request.query.allKeys) {
        NSString *value = request.query[key];
        NSString *kv;
        if ([value isEqualToString:@""]) {
            kv = [key stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"`#%^{}\"[]|\\<> "]];
        }else{
            kv = [NSString stringWithFormat:@"%@=%@",[key stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"`#%^{}\"[]|\\<> "]],[value stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"`#%^{}\"[]|\\<> "]]];
        }
        [array addObject:kv];
    }
    // 升序排序
    array = [self sortArray:array];
    NSString *arrStr = [array componentsJoinedByString:@"&"];
    return arrStr;
    
}
- (NSString *)signedHeaders:(OcrAkSKSignRequest *)request{
    NSMutableArray *array = [NSMutableArray array];
    for (NSString *key  in request.headers.allKeys) {
        [array addObject:key.lowercaseString];
    }
    array = [self sortArray:array];
    NSString *arrStr = [array componentsJoinedByString:@";"];
    return arrStr;
}

- (NSString *)authHeaderValueWithSignature:(NSString *)signature AppKey:(NSString *)appKey SignedHeaders:(NSString *)signedHeaders {
    NSString *str = [NSString stringWithFormat:@"%@ Access=%@, SignedHeaders=%@, Signature=%@", self.algorithm, appKey, signedHeaders, signature];
    return str;
}
- (NSString *)canonicalHeaders:(OcrAkSKSignRequest *)request{
    NSMutableArray *arr = [NSMutableArray array];
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    for (NSString *key in request.headers.allKeys) {
        NSString *value = request.headers[key];
        NSString *keyEncoded = key.lowercaseString;
        NSString *valueEncoded = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
        [arr addObject: [NSString stringWithFormat:@"%@:%@",keyEncoded,valueEncoded]];
        [dic setValue:valueEncoded forKey:keyEncoded];
    }
    arr = [self sortArray:arr];
    request.headers = dic;
    NSString *arrStr = [arr componentsJoinedByString:@"\n"];
    return [NSString stringWithFormat:@"%@\n",arrStr];
}
- (NSMutableArray *)sortArray:(NSMutableArray *)array{
    NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES];
    NSArray *descriptors = [NSArray arrayWithObject:descriptor];
    NSArray *sortedArray = [[array copy] sortedArrayUsingDescriptors:descriptors];
    return [sortedArray mutableCopy];
}
@end

@implementation OcrAkSKSignRequest

@end
