//
//  ZYJQNAutoZone.m
//  ZYJQiniuSDK
//
//  Created by yangsen on 2020/4/16.
//  Copyright © 2020 Qiniu. All rights reserved.
//

#import "ZYJQNAutoZone.h"
#import "ZYJQNSessionManager.h"
#import "ZYJQNZoneInfo.h"
#import "ZYJQNUpToken.h"
#import "ZYJQNResponseInfo.h"

@interface ZYJQNAutoZoneCache : NSObject
@property(nonatomic, strong)NSMutableDictionary *cache;
@end
@implementation ZYJQNAutoZoneCache

+ (instancetype)share{
    static ZYJQNAutoZoneCache *cache = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        cache = [[ZYJQNAutoZoneCache alloc] init];
        [cache setupData];
    });
    return cache;
}

- (void)setupData{
    self.cache = [NSMutableDictionary dictionary];
}

- (void)cache:(NSDictionary *)zonesInfo
     forToken:(ZYJQNUpToken *)token{
    
    NSString *cacheKey = token.index;
    if (!cacheKey || [cacheKey isEqualToString:@""]) {
        return;
    }
    
    @synchronized (self) {
        if (zonesInfo) {
            self.cache[cacheKey] = zonesInfo;
        } else {
            [self.cache removeObjectForKey:cacheKey];
        }
    }
}

- (ZYJQNZonesInfo *)zonesInfoForToken:(ZYJQNUpToken *)token{
    
    NSString *cacheKey = token.index;
    if (!cacheKey || [cacheKey isEqualToString:@""]) {
        return nil;
    }
    
    NSDictionary *zonesInfoDic = nil;
    @synchronized (self) {
        zonesInfoDic = self.cache[cacheKey];
    }
    
    if (zonesInfoDic == nil) {
        return nil;
    }
    
    ZYJQNZonesInfo *zonesInfo = [ZYJQNZonesInfo buildZonesInfoWithResp:zonesInfoDic];
    NSMutableArray *zonesInfoArray = [NSMutableArray array];
    for (ZYJQNZoneInfo *zoneInfo in zonesInfo.zonesInfo) {
        if ([zoneInfo isValid]) {
            [zonesInfoArray addObject:zoneInfo];
        }
    }
    zonesInfo.zonesInfo = [zonesInfoArray copy];
    return zonesInfo;
}

@end

@implementation ZYJQNAutoZone {
    NSString *server;
    NSMutableDictionary *cache;
    NSLock *lock;
    ZYJQNSessionManager *sesionManager;
}

- (instancetype)init{
    if (self = [super init]) {
        server = @"https://uc.qbox.me";
        cache = [NSMutableDictionary new];
        lock = [NSLock new];
        sesionManager = [[ZYJQNSessionManager alloc] initWithProxy:nil timeout:10 urlConverter:nil];
    }
    return self;
}

- (NSString *)up:(ZYJQNUpToken *)token
    zoneInfoType:(ZYJQNZoneInfoType)zoneInfoType
         isHttps:(BOOL)isHttps
    frozenDomain:(NSString *)frozenDomain {

    NSString *index = [token index];
    [lock lock];
    ZYJQNZonesInfo *zonesInfo = [cache objectForKey:index];
    [lock unlock];
    if (zonesInfo == nil) {
        return nil;
    }
    return  [self upHost:[zonesInfo getZoneInfoWithType:zoneInfoType] isHttps:isHttps lastUpHost:frozenDomain];
}

- (ZYJQNZonesInfo *)getZonesInfoWithToken:(ZYJQNUpToken *)token {
    if (token == nil) return nil;
    [lock lock];
    ZYJQNZonesInfo *zonesInfo = [cache objectForKey:[token index]];
    [lock unlock];
    return zonesInfo;
}

- (void)preQuery:(ZYJQNUpToken *)token
              on:(ZYJQNPrequeryReturn)ret {
    
    if (token == nil) {
        ret(-1, nil);
        return;
    }
    
    [lock lock];
    ZYJQNZonesInfo *zonesInfo = [cache objectForKey:[token index]];
    [lock unlock];
    
    if (zonesInfo == nil) {
        zonesInfo = [[ZYJQNAutoZoneCache share] zonesInfoForToken:token];
        [self->lock lock];
        [self->cache setValue:zonesInfo forKey:[token index]];
        [self->lock unlock];
    }
    
    if (zonesInfo != nil) {
        ret(0, nil);
        return;
    }

    //https://uc.qbox.me/v3/query?ak=T3sAzrwItclPGkbuV4pwmszxK7Ki46qRXXGBBQz3&bucket=if-pbl
    NSString *url = [NSString stringWithFormat:@"%@/v3/query?ak=%@&bucket=%@", server, token.access, token.bucket];
    [sesionManager get:url withHeaders:nil withCompleteBlock:^(ZYJQNHttpResponseInfo *httpResponseInfo, NSDictionary *respBody) {
        if (!httpResponseInfo.error) {
        
            ZYJQNZonesInfo *zonesInfo = [ZYJQNZonesInfo buildZonesInfoWithResp:respBody];
            if (httpResponseInfo == nil) {
                ret(kZYJQNInvalidToken, httpResponseInfo);
            } else {
                [self->lock lock];
                [self->cache setValue:zonesInfo forKey:[token index]];
                [self->lock unlock];
                [[ZYJQNAutoZoneCache share] cache:respBody forToken:token];
                ret(0, httpResponseInfo);
            }
        } else {
            ret(kZYJQNNetworkError, httpResponseInfo);
        }
    }];
}

@end
