//
//  TNLXThirdViewController.m
//  TwitterNetworkLayer
//
//  Created on 8/23/14.
//  Copyright © 2020 Twitter. All rights reserved.
//

#import <TwitterNetworkLayer/TwitterNetworkLayer.h>

#import "TAPI.h"

#import "TNLXAppDelegate.h"
#import "TNLXMultipartFormData.h"
#import "TNLXPlaygroundViewController.h"

@import UIKit;

#define DOWNLOAD_URL @"http://speedtest.reliableservers.com/100MBtest.bin"

@interface Dummy : NSObject
- (id)URLSessionTaskOperation;
- (id)URLSession;
@end

#define TWEET_ID 523495208437424128LL

// #define TIMEOUT_VALUE (5)

typedef void(^TNLXCompletionBlock)(TNLRequestOperation *op, TNLResponse *response);

static /*not const*/ BOOL USE_CALLBACK_REDIRECT_POLICIES = YES;

typedef NS_ENUM(NSInteger, TNLXRedirectTestPolicy)
{
    TNLXRedirectTestPolicyCallbackNoRedirect,
    TNLXRedirectTestPolicyCallbackShortendedURLRedirect,
    TNLXRedirectTestPolicyCallbackAllRedirects,

    TNLXRedirectTestPolicyAutoNoRedirect,
    TNLXRedirectTestPolicyAutoRedirect,
    TNLXRedirectTestPolicyAutoRedirectCancelAfter1,
};

@interface TNLXRedirectTestObject : NSObject <TNLRequestDelegate>

@property (nonatomic, copy) TNLRequestConfiguration *config;
@property (nonatomic) TNLXRedirectTestPolicy redirectPolicy;
@property (nonatomic) NSUInteger redirectCount;
@property (nonatomic, copy) TNLXCompletionBlock completionBlock;
@property (nonatomic) id<TNLRequest> request;

- (void)start;

@end

@interface TNLXPlaygroundViewController () <TNLRequestDelegate, NSURLConnectionDataDelegate>
{
    IBOutlet UIButton *_multiSubmitButton;
    IBOutlet UIButton *_favButton;
    IBOutlet UIButton *_unfavButton;
    IBOutlet UIButton *_loadFileButton;
    IBOutlet UIButton *_cancelFileButton;
    IBOutlet UIButton *_httpTestButton;
    IBOutlet UIButton *_httpsTwitterTestButton;
    IBOutlet UIButton *_goWithRedirectsButton;
    IBOutlet UIButton *_goWithoutRedirectsButton;
    IBOutlet UIButton *_goWithOnlyShortlinkRedirects;
    IBOutlet UIProgressView *_multiProgressView;
    IBOutlet UIProgressView *_fileProgressView;
    IBOutlet UITextField *_httpTestField;
    IBOutlet UITextField *_customURLField;
    IBOutlet UILabel *_commsStatusField;

    TNLRequestOperationQueue *_queue;
    TNLRequestOperation *_currentOperation;
    NSString *_fileDestination;
    TNLRequestOperation *_fileDownloadOp;
    NSURLConnection *_fileDownloadConnection;
    NSURLResponse *_fileDownloadConnectionResponse;
    long long _fileDownloadConnectionLoadedBytes;
    NSString *_sessionId;
    NSUInteger _taskId;
}

@end

@implementation TNLXPlaygroundViewController

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        [self prep];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]) {
        [self prep];
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)prep
{
    if (_fileDestination) {
        return;
    }

    _fileDestination = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"DownloadFolder/LargeFileDownload.bin"];
    NSFileManager *fm = [NSFileManager defaultManager];
    [fm createDirectoryAtPath:[_fileDestination stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:NULL];
    _queue = [[TNLRequestOperationQueue alloc] initWithIdentifier:NSStringFromClass([self class]).lowercaseString];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundRequestDidDownloadNotification:) name:TNLBackgroundRequestOperationDidCompleteNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    _multiSubmitButton.layer.borderWidth = 1;
    _multiSubmitButton.layer.borderColor = _multiSubmitButton.tintColor.CGColor;
    _favButton.layer.borderWidth = 1;
    _favButton.layer.borderColor = _favButton.tintColor.CGColor;
    _unfavButton.layer.borderWidth = 1;
    _unfavButton.layer.borderColor = _unfavButton.tintColor.CGColor;
    _loadFileButton.layer.borderWidth = 1;
    _loadFileButton.layer.borderColor = _loadFileButton.tintColor.CGColor;
    _cancelFileButton.layer.borderWidth = 1;
    _cancelFileButton.layer.borderColor = _cancelFileButton.tintColor.CGColor;
    _httpTestButton.layer.borderWidth = 1;
    _httpTestButton.layer.borderColor = _httpTestButton.tintColor.CGColor;
    _httpsTwitterTestButton.layer.borderWidth = 1;
    _httpsTwitterTestButton.layer.borderColor = _httpsTwitterTestButton.tintColor.CGColor;
    _goWithOnlyShortlinkRedirects.layer.borderWidth = 1;
    _goWithOnlyShortlinkRedirects.layer.borderColor = _goWithOnlyShortlinkRedirects.tintColor.CGColor;
    _goWithoutRedirectsButton.layer.borderWidth = 1;
    _goWithoutRedirectsButton.layer.borderColor = _goWithoutRedirectsButton.tintColor.CGColor;
    _goWithRedirectsButton.layer.borderWidth = 1;
    _goWithRedirectsButton.layer.borderColor = _goWithRedirectsButton.tintColor.CGColor;

    _multiProgressView.progress = 0;
    _fileProgressView.progress = 0;
    if ([[NSFileManager defaultManager] fileExistsAtPath:_fileDestination]) {
        _fileProgressView.progress = 1;
        _fileProgressView.tintColor = [UIColor greenColor];
        _loadFileButton.enabled = NO;
        _cancelFileButton.enabled = YES;
    } else {
        _fileProgressView.progress = 0;
        _fileProgressView.tintColor = [UIColor blueColor];
        _loadFileButton.enabled = YES;
        _cancelFileButton.enabled = NO;
    }

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(_communicationStatusDidUpdate:)
                                                 name:TNLXCommunicationStatusUpdatedNotification
                                               object:nil];
    _commsStatusField.text = APP_DELEGATE.communicationStatusDescription;
}

- (void)_communicationStatusDidUpdate:(NSNotification *)note
{
    NSString *status = note.userInfo[@"description"] ?: APP_DELEGATE.communicationStatusDescription;
    _commsStatusField.text = status;
}

- (IBAction)goWithRedirects:(id)sender
{
    [self goWithRedirectPolicy:USE_CALLBACK_REDIRECT_POLICIES ? TNLXRedirectTestPolicyCallbackAllRedirects : TNLXRedirectTestPolicyAutoRedirect];
}

- (IBAction)goWithNoRedirects:(id)sender
{
    [self goWithRedirectPolicy:USE_CALLBACK_REDIRECT_POLICIES ? TNLXRedirectTestPolicyCallbackNoRedirect : TNLXRedirectTestPolicyAutoNoRedirect];
}

- (IBAction)goWithOnlyShortURLRedirects:(id)sender
{
    [self goWithRedirectPolicy:USE_CALLBACK_REDIRECT_POLICIES ? TNLXRedirectTestPolicyCallbackShortendedURLRedirect : TNLXRedirectTestPolicyAutoRedirectCancelAfter1];
}

- (void)goWithRedirectPolicy:(TNLXRedirectTestPolicy)redirectPolicy
{
    _goWithOnlyShortlinkRedirects.enabled = NO;
    _goWithoutRedirectsButton.enabled = NO;
    _goWithRedirectsButton.enabled = NO;

    TNLXRedirectTestObject *testObj = [[TNLXRedirectTestObject alloc] init];
    testObj.redirectPolicy = redirectPolicy;
    testObj.request = [TNLHTTPRequest GETRequestWithURL:[NSURL URLWithString:_customURLField.text]
                                       HTTPHeaderFields:nil];
    testObj.completionBlock = ^(TNLRequestOperation *operation, TNLResponse *response) {
        self->_goWithOnlyShortlinkRedirects.enabled = YES;
        self->_goWithoutRedirectsButton.enabled = YES;
        self->_goWithRedirectsButton.enabled = YES;

        NSString *message = [NSString stringWithFormat:@"Redirect Count: %tu\nHeaders: %@\nMetrics: %@", response.metrics.redirectCount, response.info.allHTTPHeaderFields, response.metrics];
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"Response"
                                                                         message:message
                                                                  preferredStyle:UIAlertControllerStyleAlert];
        [alertVC addAction:[UIAlertAction actionWithTitle:@"OK"
                                                    style:UIAlertActionStyleCancel
                                                  handler:nil]];
        [self presentViewController:alertVC animated:YES completion:nil];
    };
    [testObj start];
}

- (void)fileDownloadComplete:(BOOL)success
{
    [_fileProgressView setProgress:1.0 animated:YES];
    _fileProgressView.progressTintColor = success ? [UIColor greenColor] : [UIColor redColor];
    _loadFileButton.enabled = !success;
    _cancelFileButton.enabled = success;
    _fileDownloadOp = nil;
}

- (void)fileDownloadStarting
{
    [_fileProgressView setProgress:0 animated:NO];
    _fileProgressView.progressTintColor = [UIColor blueColor];
    _loadFileButton.enabled = NO;
    _cancelFileButton.enabled = YES;
}

- (IBAction)fileClear:(id)sender
{
    [[NSFileManager defaultManager] removeItemAtPath:_fileDestination error:NULL];
    [_fileProgressView setProgress:0 animated:NO];
    _fileProgressView.progressTintColor = [UIColor blueColor];
    _loadFileButton.enabled = YES;
    _cancelFileButton.enabled = NO;
    [_fileDownloadOp cancelWithSource:@"Clear"];
    _fileDownloadOp = nil;
    [_fileDownloadConnection cancel];
    _fileDownloadConnection = nil;
    _fileDownloadConnectionResponse = nil;
    _fileDownloadConnectionLoadedBytes = 0;
}

- (IBAction)fileDownload:(id)sender
{
    assert(!_fileDownloadOp);
    TNLMutableRequestConfiguration * config = [TNLMutableRequestConfiguration defaultConfiguration];
    config.idleTimeout = 10;
    config.attemptTimeout = NSTimeIntervalSince1970;
    config.operationTimeout = NSTimeIntervalSince1970;
//    config.executionMode = TNLRequestExecutionModeBackground;
//    config.responseDataConsumptionMode = TNLResponseDataConsumptionModeSaveToDisk;
//    config.allowsCellularAccess = NO;

    _fileDownloadOp = [TNLRequestOperation operationWithURL:[NSURL URLWithString:DOWNLOAD_URL]
                                              configuration:config
                                                   delegate:self];

    [self fileDownloadStarting];
    [_queue enqueueRequestOperation:_fileDownloadOp];
}

- (IBAction)fileDownload_NSURLConnection_disabled:(id)sender
{
    assert(!_fileDownloadConnection);

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    request.URL = [NSURL URLWithString:DOWNLOAD_URL];
    request.timeoutInterval = 10;

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    _fileDownloadConnection = [[NSURLConnection alloc] initWithRequest:request
                                                              delegate:self
                                                      startImmediately:NO];
#pragma clang diagnostic pop
    [_fileDownloadConnection setDelegateQueue:[NSOperationQueue mainQueue]];
    [self fileDownloadStarting];
    [_fileDownloadConnection start];
}

- (void)didEnterBackground:(NSNotification *)note
{
//    if (_fileDownloadOp) {
//        NSUInteger *pointer = NULL;
//        NSUInteger i = *pointer;
//        i++;
//    }
    NSLog(@"Background Timer Remaining: %@s", @([UIApplication sharedApplication].backgroundTimeRemaining));
}

- (void)backgroundRequestDidDownloadNotification:(NSNotification *)note
{
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:_cmd withObject:note waitUntilDone:NO];
        return;
    }

    NSURLRequest *request = note.userInfo[TNLBackgroundRequestURLRequestKey];
    TNLResponse *response = note.userInfo[TNLBackgroundRequestResponseKey];
    NSUInteger taskId = [(NSNumber *)note.userInfo[TNLBackgroundRequestURLSessionTaskIdentifierKey] unsignedIntegerValue];
    NSString *sessionId = note.userInfo[TNLBackgroundRequestURLSessionConfigurationIdentifierKey];

    NSLog(@"[BG_DOWNLOAD] - %@", note);

    if (taskId == _taskId) {
        if ([sessionId isEqualToString:_sessionId]) {
            NSURL *originalURL = _fileDownloadOp.hydratedRequest.URL ?: ([_fileDownloadOp.originalRequest respondsToSelector:@selector(URL)] ? [(id)_fileDownloadOp.originalRequest URL] : nil);
            if ([request.URL.absoluteString isEqualToString:originalURL.absoluteString]) {
                NSError *error;
                BOOL success = response.info.statusCode == 200 && [response.info.temporarySavedFile moveToPath:_fileDestination error:&error];
                if (error) {
                    NSLog(@"%@ %@", NSStringFromSelector(_cmd), error);
                }
                [self fileDownloadComplete:success];
            }
        }
    }
}

- (void)complete:(BOOL)success
{
    [_multiProgressView setProgress:1.0 animated:YES];
    _multiProgressView.progressTintColor = success ? [UIColor greenColor] : [UIColor redColor];
    _multiSubmitButton.enabled = YES;
    _favButton.enabled = YES;
    _unfavButton.enabled = YES;
    _currentOperation = nil;
}

- (void)willStart
{
    [_multiProgressView setProgress:0 animated:NO];
    _unfavButton.enabled = NO;
    _favButton.enabled = NO;
    _multiSubmitButton.enabled = NO;
    _multiProgressView.progressTintColor = [UIColor blueColor];
}

- (IBAction)multiSubmit:(UIButton *)sender
{
    [self willStart];

    UIImage *image = [UIImage imageNamed:@"first"];
    NSData *jpegData = UIImageJPEGRepresentation(image, .05f);

    TAPIUploadMediaRequest *request = [[TAPIUploadMediaRequest alloc] initWithImageData:jpegData];

    _currentOperation = [[TAPIClient sharedInstance] startRequest:request
                                                       completion:^(TAPIUploadMediaResponse *response) {
                                                           [self complete:response.didSucceed];
                                                       }];
}

- (IBAction)fav:(id)sender
{
    [self willStart];

    TAPIClient *client = [TAPIClient sharedInstance];
    TAPIFavoriteCreateRequest *favRequest = [[TAPIFavoriteCreateRequest alloc] initWithStatusID:TWEET_ID];
    _currentOperation = [client startRequest:favRequest
                                  completion:^(TAPIFavoriteResponse *response) {
                                      [self complete:response.didSucceed];
                                  }];
}

- (IBAction)unfav:(id)sender
{
    [self willStart];

    TAPIClient *client = [TAPIClient sharedInstance];
    TAPIFavoriteDestroyRequest *unfavRequest = [[TAPIFavoriteDestroyRequest alloc] initWithStatusID:TWEET_ID];
    _currentOperation = [client startRequest:unfavRequest
                                  completion:^(TAPIFavoriteResponse *response) {
                                      [self complete:response.didSucceed];
                                  }];
}

- (IBAction)kill:(id)sender
{
    NSUInteger *pointer = NULL;
    NSUInteger i = *pointer;
    i++;
}

- (IBAction)testHTTP:(id)sender
{
    [_httpTestField resignFirstResponder];
    _httpTestButton.enabled = NO;
    NSInteger code = [_httpTestField.text integerValue];
    NSString *URLString = [NSString stringWithFormat:@"http://httpbin.org/status/%td", code];
    TNLRequestOperation *op = [TNLRequestOperation operationWithURL:[NSURL URLWithString:URLString]
                                                         completion:^(TNLRequestOperation *innerOp, TNLResponse *response) {
        self->_httpTestButton.enabled = YES;
        NSString *message = [NSString stringWithFormat:@"Status Code: %td", response.info.statusCode];
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"HTTP Response"
                                                                         message:message
                                                                  preferredStyle:UIAlertControllerStyleAlert];
        [alertVC addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
        [self presentViewController:alertVC animated:YES completion:nil];
    }];
    [[TNLRequestOperationQueue defaultOperationQueue] enqueueRequestOperation:op];
}

- (IBAction)testHTTPSTwitter:(id)sender
{
    [self testTwitter];
}

- (void)testTwitter
{
    _httpsTwitterTestButton.enabled = NO;
    TNLMutableRequestConfiguration *config = [TNLMutableRequestConfiguration defaultConfiguration];

//    static NSInteger swap = 0;
//    swap++;
//    switch (swap % 4) {
//        case 1:
//            config.URLCache = [NSURLCache tnl_sharedURLCacheProxy];
//            break;
//        case 2:
//            config.URLCache = [NSURLCache tnl_impotentURLCache];
//            break;
//        case 3:
//            config.URLCache = [NSURLCache sharedURLCache];
//            break;
//        case 0:
//        default:
//            config.URLCache = nil;
//            break;
//    }

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://www.twitter.com"]];

    TNLXCompletionBlock block = ^(TNLRequestOperation *innerOp, TNLResponse *response) {
        assert([NSThread isMainThread]);
        self->_httpsTwitterTestButton.enabled = YES;
        NSString *message = [NSString stringWithFormat:@"Metrics: %@", response.metrics];
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"HTTP Response"
                                                                         message:message
                                                                  preferredStyle:UIAlertControllerStyleAlert];
        [alertVC addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
        [self presentViewController:alertVC animated:YES completion:nil];
        NSLog(@"(%zi) (CL: %@) %@ %@", response.info.statusCode, [response.info valueForResponseHeaderField:@"Content-Length"], response.operationError ?: @"", response.metrics);
        // TLSLogDebug(NSStringFromClass([self class]), @"Headers: %@", response.info.allHTTPHeaderFields);
    };

    TNLXRedirectTestObject *testObj = [[TNLXRedirectTestObject alloc] init];
    testObj.request = request;
    testObj.redirectPolicy = 0; // to test without redirects set this to -1
    testObj.completionBlock = block;
    testObj.config = config;
    [testObj start];
}

- (void)tnl_requestOperation:(TNLRequestOperation *)op
              hydrateRequest:(id<TNLRequest>)request
                  completion:(TNLRequestHydrateCompletionBlock)complete
{
    if (op == _fileDownloadOp) {
        complete(nil, nil);
        return;
    }

    assert([request isKindOfClass:[TNLXMultipartFormDataRequest class]]);

#if TIMEOUT_VALUE
    sleep(TIMEOUT_VALUE * 2);
#endif

    NSError *error = nil;
    request = [(TNLXMultipartFormDataRequest *)request generateRequestWithUploadFormat:TNLXMultipartFormDataUploadFormatFile
                                                                                 error:&error];
    complete(request, error);
}

- (void)tnl_requestOperation:(TNLRequestOperation *)op
      didTransitionFromState:(TNLRequestOperationState)oldState
                     toState:(TNLRequestOperationState)newState
{
    if (op == _fileDownloadOp) {
//        if (newState == TNLRequestOperationStateRunning) {
//            [(NSURLSession *)[(id)[(id)op URLSessionTaskOperation] URLSession] getTasksWithCompletionHandler:^(NSArray *nt, NSArray *ut, NSArray *dt) {
//                NSLog(@"\ndata: %@\nupload: %@\ndownload: %@", nt, ut, dt);
//            }];
//        }
        return;
    }

    if (newState == TNLRequestOperationStateRunning) {
#if TIMEOUT_VALUE
        sleep(TIMEOUT_VALUE * 2);
#endif
    }
}

- (void)tnl_requestOperation:(TNLRequestOperation *)op
        didStartRequestWithURLSessionTaskIdentifier:(NSUInteger)taskId
        URLSessionConfigurationIdentifier:(NSString *)configId
        URLSessionSharedContainerIdentifier:(NSString *)sharedContainerIdentifier
        isBackgroundRequest:(BOOL)isBackgroundRequest
{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (op != self->_fileDownloadOp) {
            return;
        }

        self->_sessionId = configId;
        self->_taskId = taskId;
    });
}

- (void)tnl_requestOperation:(TNLRequestOperation *)op
     didCompleteWithResponse:(TNLResponse *)response
{
    assert([NSThread isMainThread]);

    NSURL *originalURL = [op.originalRequest respondsToSelector:@selector(URL)] ? [(id)op.originalRequest URL] : nil;
    if ([originalURL.absoluteString isEqualToString:DOWNLOAD_URL]) {
        NSLog(@"[BG_DOWNLOAD] - %@ %@", op.originalRequest, response);
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"BG Download"
                                                                         message:[NSString stringWithFormat:@"%@", response]
                                                                  preferredStyle:UIAlertControllerStyleAlert];
        [alertVC addAction:[UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleCancel handler:nil]];
        [self presentViewController:alertVC animated:YES completion:nil];
        return;
    }

    NSLog(@"%@ %@ %@ %@", NSStringFromSelector(_cmd), op, response, response.metrics);
    [self complete:!response.operationError && 200 == response.info.statusCode];
}

- (void)tnl_requestOperation:(TNLRequestOperation *)op
     didUpdateUploadProgress:(float)uploadProgress
{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (op == self->_fileDownloadOp) {
            return;
        }

        [self->_multiProgressView setProgress:uploadProgress animated:YES];
    });
}

- (void)tnl_requestOperation:(TNLRequestOperation *)op
   didUpdateDownloadProgress:(float)downloadProgress
{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (op != self->_fileDownloadOp) {
            return;
        }

        [self->_fileProgressView setProgress:downloadProgress animated:YES];
    });
}

#pragma mark Connection

- (void)connection:(NSURLConnection *)connection
    didReceiveData:(NSData *)data
{
    _fileDownloadConnectionLoadedBytes += data.length;
    _fileProgressView.progress = (float)((double)_fileDownloadConnectionLoadedBytes / (double)_fileDownloadConnectionResponse.expectedContentLength);
}

- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
    _fileDownloadConnectionResponse = response;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self _connection:connection
          didFinishedWithResponse:_fileDownloadConnectionResponse
          error:nil];
}

- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error
{
    [self _connection:connection
          didFinishedWithResponse:_fileDownloadConnectionResponse
          error:error];
}

- (void)_connection:(NSURLConnection *)connection
        didFinishedWithResponse:(NSURLResponse *)response
        error:(NSError *)error
{
    NSLog(@"[BG_DOWNLOAD] - %@ %@", connection.originalRequest, response);
    NSMutableDictionary *info = [[NSMutableDictionary alloc] init];
    if (response) {
        info[@"response"] = response;
    }
    if (error) {
        info[@"error"] = error;
    }
    info[@"URL"] = connection.originalRequest.URL;
    UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"BG Download"
                                                                     message:[NSString stringWithFormat:@"%@", info]
                                                              preferredStyle:UIAlertControllerStyleAlert];
    [alertVC addAction:[UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleCancel handler:nil]];
    [self presentViewController:alertVC animated:YES completion:nil];
}

@end

@implementation TNLXRedirectTestObject

- (void)start
{
    TNLMutableRequestConfiguration *config = [self.config mutableCopy] ?: [TNLMutableRequestConfiguration defaultConfiguration];
    switch (self.redirectPolicy) {
        case TNLXRedirectTestPolicyAutoNoRedirect:
            config.redirectPolicy = TNLRequestRedirectPolicyDontRedirect;
            break;
        case TNLXRedirectTestPolicyAutoRedirect:
        case TNLXRedirectTestPolicyAutoRedirectCancelAfter1:
            config.redirectPolicy = TNLRequestRedirectPolicyDoRedirect;
            break;
        case TNLXRedirectTestPolicyCallbackNoRedirect:
        case TNLXRedirectTestPolicyCallbackAllRedirects:
        case TNLXRedirectTestPolicyCallbackShortendedURLRedirect:
            config.redirectPolicy = TNLRequestRedirectPolicyUseCallback;
            break;
    }
    TNLRequestOperation *op = [TNLRequestOperation operationWithRequest:self.request
                                                          configuration:config
                                                               delegate:self];
    op.context = self;
    [[TNLRequestOperationQueue defaultOperationQueue] enqueueRequestOperation:op];
}

- (void)tnl_requestOperation:(TNLRequestOperation *)op
     willRedirectFromRequest:(NSURLRequest<TNLRequest> *)fromRequest
                withResponse:(NSHTTPURLResponse *)response
                   toRequest:(NSURLRequest<TNLRequest> *)providedRequest
                  completion:(TNLRequestRedirectCompletionBlock)completionBlock
{
    NSURLRequest *toRequest = providedRequest;
    TNLXRedirectTestPolicy policy = self.redirectPolicy;
    if (policy == TNLXRedirectTestPolicyCallbackNoRedirect) {
        toRequest = nil;
    } else if (policy == TNLXRedirectTestPolicyCallbackShortendedURLRedirect) {
        if (toRequest.URL.host.length > 8) {
            toRequest = nil;
        } else {
            NSArray *components = toRequest.URL.pathComponents;
            if (components.count > 2) {
                toRequest = nil;
            } else if ([(NSString *)components.lastObject length] > 16) {
                toRequest = nil;
            }
        }
    }
    if (toRequest) {
        NSLog(@"Redirecting to %@", toRequest.URL);
    } else {
        NSLog(@"Stopping redirect (was %@)", providedRequest.URL);
    }
    completionBlock(toRequest);
}

- (void)tnl_requestOperation:(TNLRequestOperation *)op
        didRedirectFromURLRequest:(NSURLRequest *)fromRequest
        toURLRequest:(NSURLRequest *)toRequest
{
    self.redirectCount++;
    if (self.redirectCount > 1 && self.redirectPolicy == TNLXRedirectTestPolicyAutoRedirectCancelAfter1) {
        [op cancelWithSource:@"TNLXRedirectTestPolicyAutoRedirectCancelAfter1"];
    }
}

- (void)tnl_requestOperation:(TNLRequestOperation *)op
        didCompleteWithResponse:(TNLResponse *)response
{
    TNLXCompletionBlock block = self.completionBlock;
    self.completionBlock = nil;
    if (block) {
        block(op, response);
    }
}

@end
