//
//  BPDownloader.m
//  BreakPointDownload
//
//  Created by 黄亚州 on 2017/5/30.
//  Copyright © 2017年 黄亚州. All rights reserved.
//

#import "BPDownloader.h"
#import "BPDownloadContent.h"
#import "BPFileManager.h"
#import <CommonCrypto/CommonCrypto.h>

typedef NS_ENUM(NSUInteger, EDownloadFinishType) {
    EDownloadNone,    //重新下载
    EDownloadEnd,     //已下载完成
    EDownloadRange,   //断点下载
};

@interface BPDownloader ()

@property (nonatomic, copy) NSString *downloadFilePath;

@property (nonatomic, assign) long long startLenght;
@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
@property (atomic, assign) NSTimeInterval timeStamp; // 单写多读

@end

@implementation BPDownloader

- (void)startDownload
{
    __weak typeof(self)weakSelf = self;
    [self getFileHead:^(NSDictionary *headerFields) {
        NSLog(@"download file cache path %@", self.aContent.cacheFilePath);
        long long length = [headerFields[@"Content-Length"] longLongValue];
        weakSelf.aContent.serverFileSize = length;
        NSInteger type = [weakSelf needDownload:length];
        switch (type) {
            case EDownloadNone:
                [weakSelf downloadWithStart:-1];
                break;
                
            case EDownloadRange:
                [weakSelf downloadWithStart:[weakSelf getLocalFileLength]];
                break;
                
            case EDownloadEnd:
                // 成功
                [weakSelf downloadSuccess];
                break;
                
            default:
                break;
        }
    }];
}

- (void)cancel
{
    if (self.dataTask)
    {
        [self.dataTask suspend];
        [self.dataTask cancel];
    }
    self.dataTask = nil;
    self.hasCancel = YES;
}

// range下载
- (void)downloadWithStart:(long long)start
{
    if (self.hasCancel == YES) { // 任务已经被取消了
        [self downloadFailWithError:[NSError errorWithDomain:@"downloadCancel" code:-999 userInfo:nil]];
        return;
    }

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.aContent.urlString]];
    if (start > 0) {
        NSString *requestRange = [NSString stringWithFormat:@"bytes=%llu-", start];
        [request setValue:requestRange forHTTPHeaderField:@"Range"];
    }
    
    self.dataTask = [self.session dataTaskWithRequest:request];
    self.dataTask.taskDescription = [self MD5String:self.aContent.urlString];
    self.startLenght = start;
    [self.dataTask resume];
}

- (NSString *)MD5String:(NSString *)str {
    if([str length] == 0)
        return nil;
    
    const char *value = [str UTF8String];
    
    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(value, (CC_LONG)strlen(value), outputBuffer);
    
    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for (NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++) {
        [outputString appendFormat:@"%02x",outputBuffer[count]];
    }
    
    return outputString;
    
}

#pragma mark - 请求封装，获取文件头信息 从0下载 断点下载

// 获取请求头信息
- (void)getFileHead:(void (^)(NSDictionary *headerFields))aBlock{
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.aContent.urlString]];
    request.HTTPMethod = @"HEAD";
    
    __weak typeof(self)weakSelf = self;
    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error != nil) {
            [weakSelf downloadFailWithError:error];
            return;
        }
        
        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            aBlock(((NSHTTPURLResponse*)response).allHeaderFields);
        }
    }];
    
    [dataTask resume];
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
    
    [self saveFileData:data];
    
    NSTimeInterval newTime = [NSDate date].timeIntervalSince1970;
//    if (newTime - self.timeStamp < 1.0) {
//        if (dataTask.countOfBytesReceived != dataTask.countOfBytesExpectedToReceive) {
//            return;
//        }
//    }
    self.timeStamp = newTime;
    if (self.downloadProgress) {
        self.downloadProgress(dataTask.countOfBytesReceived + self.startLenght,dataTask.countOfBytesExpectedToReceive + self.startLenght);
    }
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    if (error == nil) {
        [self downloadSuccess];
    }else{
        [self downloadFailWithError:error];
    }
}

#pragma mark - 失败成功回调
- (void)downloadSuccess{
    if (self.successBlock) {
        dispatch_async(dispatch_get_main_queue(), ^{
            self.successBlock(self);
        });
    }
}

- (void)downloadFailWithError:(NSError *)aError{
    NSLog(@"head object failed %@",aError);
    if (self.failBlock) {
        dispatch_async(dispatch_get_main_queue(), ^{
            self.failBlock(self,aError);
        });
    }
}

// 写入文件
- (void)saveFileData:(NSData*)aData{
    [BPFileManager saveData:aData toFilePath:self.downloadFilePath];
}

#pragma mark - 下载状态判断
- (EDownloadFinishType)needDownload:(long long)length{
    long long localLength = [self getLocalFileLength];
    
    if (localLength == 0) {
        return EDownloadNone;
    }
    
    if (localLength == length) {
        return EDownloadEnd;
    }
    
    //本地大于服务端 删除后重下
    if (localLength > length) {
        [self deleteLocalFile];
        return EDownloadNone;
    }
    
    // 本地小于服务端 就 断点下载
    return EDownloadRange;
}

#pragma mark - 文件处理
// 获取本地文件的大小长度
- (long long)getLocalFileLength{
    return [BPFileManager getLengthForFilePath:self.downloadFilePath];
}

// 删除文件
- (void)deleteLocalFile{
    return [BPFileManager deleteLocalFilePath:self.downloadFilePath];
}

#pragma mark - lazy load

- (NSString *)downloadFilePath{
    if (!_downloadFilePath) {
        _downloadFilePath = self.aContent.cacheFilePath;
    }
    return _downloadFilePath;
}

@end
