//
//  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
