//
//  CLResourceDownloadInfo.h
//  mpl
//
//  Created by Emil Pettersson on 10/04/16.
//  Copyright © 2016 castLabs GmbH. All rights reserved.
//

#import "CLDownloadStats.h"
#import "CLRangedURL.h"

@class CLQualityDownloadInfo;
@class CLResourceDownloadInfo;

@interface CLResourceId : NSObject

#pragma mark Properties

@property (nullable, nonatomic, readonly) NSString* manifestURL;
@property (nullable, nonatomic, readonly) NSString* qualityId;
@property (nonatomic, readonly) NSUInteger resourceIndex;
@property (nonatomic, readonly) CLDownloadStatus status;

#pragma mark Serialization

- (nullable NSString*)serializeToJSON;

#pragma mark Initialization & Creation

- (nullable instancetype)initWithResource:(nonnull CLResourceDownloadInfo*)resource;
- (nullable instancetype)initWithJSONString:(nonnull NSString*)json;

+ (nullable instancetype)resourceIdWithResource:(nonnull CLResourceDownloadInfo*)resource;
+ (nullable instancetype)resourceIdWithJSONString:(nonnull NSString*)json;

@end

@protocol CLSessionController <NSObject>

/**
 * The controller download session.
 */
@property (nonnull, readonly) NSURLSession* downloadSession;

/**
 * Called when a new task has been created using the controller download session.
 */
- (void)resource:(nonnull CLResourceDownloadInfo*)resource attachTask:(nonnull NSURLSessionDownloadTask*)task;

/**
 * Called when a new task has been disposed using the controller download session.
 */
- (void)resource:(nonnull CLResourceDownloadInfo*)resource detachTask:(nonnull NSURLSessionDownloadTask*)task;

@end

@interface CLResourceDownloadInfo <CLDownloadStats> : NSObject

#pragma mark Properties

/**
 * The downloading resource.
 */
@property (nonnull, nonatomic, readonly) CLRangedURL* resource;

/**
 * The destination path for the download relative to the root download path.
 */
@property (nonnull, nonatomic, readonly) NSString* relativeResourcePath;

/**
 * The destination file for the download.
 */
@property (nonnull, nonatomic, readonly) NSString* resourcePath;

/**
 * The parent quality info.
 */
@property (nullable, weak, nonatomic, readonly) CLQualityDownloadInfo* quality;

/**
 * The index of the resource.
 */
@property (nonatomic, readonly) NSUInteger index;

/**
 * The download sessin controller.
 */
@property (nullable, weak, nonatomic, readonly) id<CLSessionController> controller;

/**
 * Additionla headers to include in download requests.
 */
@property (nullable, nonatomic) NSDictionary<NSString*, NSString*>* additionalHeaders;

/**
 * The task responsible for downloading the resource (or null if it is not downloading).
 */
@property (nullable, readonly) NSURLSessionDownloadTask* downloadTask;

/**
 * The status of the resource download (see CLDownloadStatus).
 */
@property (nonatomic, readonly) CLDownloadStatus status;

/**
 * Indicates if download is complete (does not indicate failure or success).
 */
@property (nonatomic, readonly) BOOL completed;

/**
 * Indicates if download failed.
 */
@property (nonatomic, readonly) BOOL failed;

/**
 * If the download has failed this property returns the error, otherwise `nil` is returned.
 */
@property (nullable, nonatomic, readonly) NSError* error;

/**
 * The maximum number of reactivations to allow.
 */
@property (nonatomic) NSUInteger maxReactivations;

/**
 * The number of reactivations attempted.
 */
@property (nonatomic, readonly) NSUInteger reactivations;

#pragma mark Control APIs

/**
 * Initiate download but leave it in paused state.
 *
 * @return YES if activation was successful, NO if resource completed or already active.
 */
- (BOOL)activate;

/**
 * Re-initiate completed download (clears completion state) but leave it in paused state.
 *
 * @return YES if activation was successful, NO if resource was already active.
 */
- (BOOL)reactivate;

/**
* Re-initiate completed download with the already pre-downloaded data (clears completion state) but leave it in paused state.
*
* @return YES if activation was successful, NO if resource was already active.
*/
- (BOOL)reactivateWithData:(nonnull NSData *)data;

/**
 * Re-attach a download task that is in progress to the resource.
 *
 * @return YES if attachment was successful, NO if not.
 */
- (BOOL)reattachWithStatus:(CLDownloadStatus)status toTask:(nonnull NSURLSessionDownloadTask*)task;

/**
 * Pause download.
 *
 * @return YES if pause was successful, NO if resource was not running.
 */
- (BOOL)pause;

/**
 * Resume download.
 *
 * @return YES if resume was successful, NO if resource was not paused.
 */
- (BOOL)resume;

/**
 * Cancel download.
 *
 * @return YES if cancellation was successful, NO if resource was not active.
 */
- (BOOL)cancel;

/**
 * Clear any error state for the download.
 *
 * @return YES if an error was cleared, NO if not.
 */
- (BOOL)clear;

/**
 * Reset download stats.
 */
- (void)reset;

/**
 * Complete resource with error (which may be `nil` if successful).
 */
- (void)completeWithError:(nullable NSError*)error;

/**
 * Complete resource with preloaded size.
 */
- (void)completeWithBytesPreloaded:(int64_t)preloaded;

/**
 * Update downloaded and expected bytes for resource.
 */
- (void)bytesDownloaded:(int64_t)downloaded andExpected:(int64_t)expected;

#pragma mark <CLDownloadStats>

/**
 * Size value in bytes, either precise or estimated (see CLDownloadSize).
 */
@property (nonatomic, readonly) CLDownloadSize expectedBytes;

/**
 * Number of bytes downloaded.
 */
@property (nonatomic, readonly) int64_t downloadedBytes;

/**
 * Progress in 0.0-1.0 scaled percentage, either precise or estimated (see CLDownloadProgress).
 */
@property (nonatomic, readonly) CLDownloadProgress progress;

#pragma mark Initialization & Creation

/**
 * Initialize a CLResourceDownloadInfo instance.
 */
- (nullable instancetype)initWithResource:(nonnull CLRangedURL*)resource
                             downloadPath:(nonnull NSString*)downloadPath
                                  quality:(nonnull CLQualityDownloadInfo*)quality
                                    index:(NSUInteger)index
                             expectedSize:(CLDownloadSize)expectedSize
                            andController:(nonnull id<CLSessionController>)controller;

/**
 * Allocate & initialize a CLResourceDownloadInfo instance.
 */
+ (nullable instancetype)infoWithResource:(nonnull CLRangedURL*)resource
                             downloadPath:(nonnull NSString*)downloadPath
                                  quality:(nonnull CLQualityDownloadInfo*)quality
                                    index:(NSUInteger)index
                             expectedSize:(CLDownloadSize)expectedSize
                            andController:(nonnull id<CLSessionController>)controller;

@end
