//
//  BJLDownloadViewController.m
//  BJPlayerManagerUI_Example
//
//  Created by MingLQ on 2018-04-03.
//  Copyright © 2018 oushizishu. All rights reserved.
//

#import <BJLiveBase/BJLiveBase.h>
#import <BJLiveBase/BJLiveBase+UIKit.h>
#import <BJLiveBase/BJLYYFPSLabel.h>

#import <BJVideoPlayerCore/BJVideoPlayerCore.h>
#import <BJVideoPlayerCore/BJVDownloadManager.h>
#import <BJVideoPlayerCore/BJVDownloadManager+migration.h>
#import <BJPlaybackUI/BJPlaybackUI.h>

#import "BJVDownloadViewController.h"
#import "PMLocalViewViewController.h"
#import "PUPlayOptionsManager.h"

NSDictionary<NSString *, NSString *> *BJLDownloadVideoTokens(void) {
    static NSDictionary<NSString *, NSString *> *tokens = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if ([BJVAppConfig sharedInstance].deployType == BJVDeployType_test) {
            tokens = @{ @"223722": @"yBxm0_WYw9QJNxj5P-sSMw9VQLyKdP-E6SI-PXBVmSptU_-fFrX50w",
                        @"222926": @"M1S1NfVsV8HINvZ_IIr3exqdzpxzkQBDI5WltjJ1mRplbsUh64OrYw",
                        @"223227": @"92hs7caR0hbINvZ_IIr3ez8ZND73B724I5WltjJ1mRplbsUh64OrYw",
                        @"412725": @"Xp4A6rLuppba5pEg8imbnT9euaJfUWpmO7SkzU5osEJ8YSQXs9Jt5g"
            };
        }
        else {
            tokens = @{ @"8858803": @"hIExVeSyq2pMyA0LsBVeTI2XgX3R-lJgNvym64-ZPCmGHUs6gMVBgg",
                        @"8858809": @"v1sJsy5l8x_meGWgWTNJpKOFuwTXgOC1pqG-9OSSXIWyUWsxuKgd8g",
                        @"8858825": @"lWMO9leBaDJMyA0LsBVeTAoKD7IZr7fkNvym64-ZPCmGHUs6gMVBgg",
                        @"8858931": @"-v9fBtlAIIlMyA0LsBVeTFI3JYpgtHQoNvym64-ZPCmGHUs6gMVBgg",
                        @"8858934": @"p8Ps5KhErA9MyA0LsBVeTLeNHbW34v8PNvym64-ZPCmGHUs6gMVBgg",
                        @"8858944": @"kklyUn8x8qBMyA0LsBVeTE_IJGWg0yFDNvym64-ZPCmGHUs6gMVBgg",
                        @"8858956": @"vt6NlMBtLB9MyA0LsBVeTI1fq3_YtKoqNvym64-ZPCmGHUs6gMVBgg",
                        @"8858963": @"CkPPvcwmL9lMyA0LsBVeTF4_63qiz8GaNvym64-ZPCmGHUs6gMVBgg",
                        @"8859024": @"PqeMKtN5zF9MyA0LsBVeTDUtXPelLOHXNvym64-ZPCmGHUs6gMVBgg",
                        @"8859030": @"RutsR-66cAVMyA0LsBVeTBOJx-FiFt0rNvym64-ZPCmGHUs6gMVBgg",
                        @"8859034": @"ZwivroLvFDlMyA0LsBVeTJzBreJBS53JNvym64-ZPCmGHUs6gMVBgg",
                        @"8859042": @"mQHwNHJ5i35MyA0LsBVeTKQl6hoFiyCSNvym64-ZPCmGHUs6gMVBgg",
                        @"8859063": @"P1ux-0BdTnFMyA0LsBVeTJmQhJZo92T2Nvym64-ZPCmGHUs6gMVBgg",
                        @"8859080": @"eBU3pTR48uBMyA0LsBVeTKOO3mL3KZ_3Nvym64-ZPCmGHUs6gMVBgg",
                        @"8859115": @"Bb7UGo1L4ABMyA0LsBVeTDL1UHMENNojNvym64-ZPCmGHUs6gMVBgg",
                        @"8859165": @"qjeNXuL3wSZMyA0LsBVeTL4r7CMiBYl_Nvym64-ZPCmGHUs6gMVBgg",
                        @"8859185": @"0kuWDmF1BCpMyA0LsBVeTGxSfICioxJWNvym64-ZPCmGHUs6gMVBgg",
                        @"8859218": @"58cxakjxLZpMyA0LsBVeTB47O2EXSXukNvym64-ZPCmGHUs6gMVBgg",
                        @"8859441": @"pC5xcEKw6iZMyA0LsBVeTO_EQVw8GFJGNvym64-ZPCmGHUs6gMVBgg",
                        @"8859500": @"dGKMhxxH8mdMyA0LsBVeTCfcA5gp_lBENvym64-ZPCmGHUs6gMVBgg",
                        @"8859511": @"y4LqgjYPngFMyA0LsBVeTDGPwH4hwV3VNvym64-ZPCmGHUs6gMVBgg",
                        @"8992195": @"24FkI8TrRrVMyA0LsBVeTBpzWCwdkRYwNvym64-ZPCmGHUs6gMVBgg",
                        @"8992197": @"2auaJUkmH9BMyA0LsBVeTOMppfiVr_ZPNvym64-ZPCmGHUs6gMVBgg",
                        @"8992259": @"ab-XLit2UmBMyA0LsBVeTISnMWqNdAJeNvym64-ZPCmGHUs6gMVBgg" };
        }
    });
    return tokens;
}

FOUNDATION_EXPORT NSDictionary<NSString *, NSString *> *BJLDownloadPlaybackTokens(void) {
    static NSDictionary<NSString *, NSString *> *tokens = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if ([BJVAppConfig sharedInstance].deployType == BJVDeployType_test) {
            tokens = @{ @"18082833153338": @"HYhriah36zjINvZ_IIr3e92IJbprfJsvsWZDArN_84vWOLKblLYhI5zjJTEfqbHxCqdH1zJ1Si0",
                        @"18082833153578": @"6_dEze3BbkbINvZ_IIr3e92IJbprfJsvlYivwXaYS2HWOLKblLYhI5zjJTEfqbHxCqdH1zJ1Si0",
                        @"18082833155370": @"xnRyc-e7z4TINvZ_IIr3e92IJbprfJsvlqag7FnYP6PWOLKblLYhI5zjJTEfqbHxCqdH1zJ1Si0",
                        @"18082833153322": @"I1roEuLRFdvINvZ_IIr3e92IJbprfJsvcdfSqTu16CHWOLKblLYhI5zjJTEfqbHxCqdH1zJ1Si0" };
        }
        else {
            tokens = @{
                @"18121856439323-201812251": @"YBNpl56vh_n6GBtNSJkwA6Bm9iXSfd0pI5Z19POKRiip3A5MMO7adA"};
        }
    });
    return tokens;
}

#pragma mark -

static const CGFloat imageSize = 48.0, margin = 5.0, rowHeight = imageSize + margin * 2;

@interface BJVDownloadItemCell : UITableViewCell

@property (nonatomic, copy) void (^updatePriority)(float priority, BJVDownloadItemCell *cell);

- (void)tryToUpdateWithItem:(BJVDownloadItem *)item;
- (void)updateWithItem:(BJVDownloadItem *)item;

- (void)updateWithModel:(PMDownloadModel *)model migrated:(BOOL)migrated;

@end

@interface BJVDownloadItemCell ()

@property (nonatomic) BJLProgress cachedProgress;
@property (nonatomic) long long cachedBytesPerSecond;

@property (nonatomic) UIView *progressView;
@property (nonatomic) BJLConstraint *progressViewWidthConstraint;

@property (nonatomic) UILabel *priorityLabel;
@property (nonatomic) UIStepper *priorityStepper;

@end

@implementation BJVDownloadItemCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
    if (self) {
        if (@available(iOS 9.0, *)) self.textLabel.font = [UIFont monospacedDigitSystemFontOfSize:[UIFont systemFontSize] weight:UIFontWeightRegular];
        self.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
        self.textLabel.backgroundColor = [UIColor clearColor];
        
        if (@available(iOS 9.0, *)) self.detailTextLabel.font = [UIFont monospacedDigitSystemFontOfSize:[UIFont smallSystemFontSize] weight:UIFontWeightLight];
        self.detailTextLabel.backgroundColor = [UIColor clearColor];
        
        self.accessoryType = UITableViewCellAccessoryDetailButton;
        
        self.progressView = ({
            UIView *progressView = [UIView new];
            progressView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.3];
            [self.contentView insertSubview:progressView atIndex:0];
            progressView;
        });
        [self.progressView bjl_makeConstraints:^(BJLConstraintMaker *make) {
            make.right.top.bottom.equal.to(self.bjl_safeAreaLayoutGuide);
            self.progressViewWidthConstraint =
            make.width.equal.to(self.bjl_safeAreaLayoutGuide).multipliedBy(1.0 - 0.0).constraint;
        }];
        
        if (![reuseIdentifier hasPrefix:@"pm-"]) {
            self.priorityLabel = ({
                UILabel *label = [UILabel new];
                if (@available(iOS 9.0, *)) label.font = [UIFont monospacedDigitSystemFontOfSize:[UIFont systemFontSize] weight:UIFontWeightRegular]; 
                [self.contentView addSubview:label];
                bjl_return label;
            });
            self.priorityStepper = ({
                UIStepper *stepper = [UIStepper new];
                stepper.minimumValue = 0.0;
                stepper.maximumValue = 1.0;
                stepper.stepValue = 0.25;
                stepper.value = 0.5;
                [self.contentView addSubview:stepper];
                bjl_return stepper;
            });
            
            [self.priorityLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
            [self.priorityLabel bjl_makeConstraints:^(BJLConstraintMaker *make) {
                make.right.equal.to(self.contentView).inset(5.0);
                make.top.equal.to(self.contentView).inset(5.0);
            }];
            [self.priorityStepper bjl_makeConstraints:^(BJLConstraintMaker *make) {
                make.right.equal.to(self.contentView).inset(5.0);
                make.bottom.equal.to(self.contentView).inset(5.0);
            }];
            
            [self.priorityStepper bjl_addHandler:^(UIStepper *stepper, UIControlEvents event) {
                if (self.updatePriority) self.updatePriority(stepper.value, self);
            } forControlEvents:UIControlEventValueChanged];
        }
        
        self.selectionStyle = UITableViewCellSelectionStyleNone;
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    self.imageView.frame = CGRectMake(margin * 2, margin, imageSize, imageSize);
    
    CGFloat contentViewWidth = CGRectGetWidth(self.contentView.bounds);
    CGFloat contentViewHeight = CGRectGetHeight(self.contentView.bounds);
    
    self.textLabel.frame = bjl_set(self.textLabel.frame, {
        set.origin.x = CGRectGetMaxX(self.imageView.frame) + margin * 2;
        set.origin.y = 5.0;
        set.size.width = (contentViewWidth
                          - CGRectGetMinX(set)
                          - 50.0); // (self.priorityStepper ? CGRectGetWidth(self.priorityStepper.frame) : 0)
        set.size.height = contentViewHeight / 2 - 5.0;
    });
    
    self.detailTextLabel.frame = bjl_set(self.detailTextLabel.frame, {
        set.origin.x = CGRectGetMinX(self.textLabel.frame);
        set.origin.y = contentViewHeight / 2;
        set.size.width = CGRectGetWidth(self.textLabel.frame);
        set.size.height = contentViewHeight / 2 - 5.0;
    });
}

- (void)prepareForReuse {
    [super prepareForReuse];
    self.cachedProgress = BJLProgressMake(0, 0);
    self.cachedBytesPerSecond = - 1;
}

- (void)tryToUpdateWithItem:(BJVDownloadItem *)item {
    if ([item compareWithProgress:self.cachedProgress bytesPerSecond:self.cachedBytesPerSecond]) {
        [self updateWithItem:item];
    }
}

- (void)updateWithItem:(BJVDownloadItem *)item {
    self.cachedProgress = item.progress;
    self.cachedBytesPerSecond = item.bytesPerSecond;
    
    NSArray<NSString *> * const byteUnits = @[ @"B", @"KB", @"MB", @"GB", @"TB", @"PB" ];
    
    double totalSize = item.totalSize;
    NSInteger totalSizeUnitIndex = 0;
    while (totalSize >= 1024 && totalSizeUnitIndex < byteUnits.count) {
        totalSize /= 1024;
        totalSizeUnitIndex++;
    }
    
    long long bytesPerSecond = self.cachedBytesPerSecond;
    NSInteger bytesUnitIndex = 0;
    while (bytesPerSecond >= 1024 && bytesUnitIndex < byteUnits.count) {
        bytesPerSecond /= 1024;
        bytesUnitIndex++;
    }
    
    self.textLabel.text = item.playInfo.title.length ? item.playInfo.title : item.itemIdentifier;
    
    self.detailTextLabel.text = [NSString stringWithFormat:@"%@"
                                 " %tux"
                                 " %.2f%@"
                                 " %.1f%%"
                                 " %lld%@/s",
                                 [self stringFromItemState:item.state error:item.error],
                                 item.downloadFiles.count,
                                 totalSize, byteUnits[totalSizeUnitIndex],
                                 self.cachedProgress.fractionCompleted * 100,
                                 bytesPerSecond, byteUnits[bytesUnitIndex]];
    
    [self.progressView bjl_updateConstraints:^(BJLConstraintMaker *make) {
        [self.progressViewWidthConstraint uninstall];
        self.progressViewWidthConstraint =
        make.width.equal.to(self.bjl_safeAreaLayoutGuide).multipliedBy(1.0 - self.cachedProgress.fractionCompleted).constraint;
    }];
    
    self.imageView.contentMode = UIViewContentModeScaleAspectFill;
    self.imageView.clipsToBounds = YES;
    self.imageView.image = (item.coverImageFile.completed
                            ? [UIImage imageWithContentsOfFile:item.coverImageFile.filePath]
                            : nil);
    if (!self.imageView.image) {
        [self.imageView bjl_setImageWithURL:item.coverImageFile.sourceURL
                                placeholder:[UIImage bjl_imageWithColor:[UIColor grayColor]]
                                 completion:nil];
    }
    
    self.priorityLabel.text = [NSString stringWithFormat:@"P%g", item.priority];
    self.priorityStepper.value = item.priority;
}

- (NSString *)stringFromItemState:(BJLDownloadItemState)state error:(nullable BJLError *)error {
    switch (state) {
        case BJLDownloadItemState_running:
            return @"⏸";
        case BJLDownloadItemState_paused:
            return @"▶️";
        case BJLDownloadItemState_completed:
            return error ? @"❎" : @"✅";
        default: // BJLDownloadItemState_invalid
            return @"❌";
    }
}

- (void)updateWithModel:(PMDownloadModel *)model migrated:(BOOL)migrated {
    float progress = (model.totalLength <= 0 ? 0.0
                      : model.receivedSize > model.totalLength ? 1.0
                      : (float)model.receivedSize / model.totalLength);
    
    NSArray<NSString *> * const byteUnits = @[ @"B", @"KB", @"MB", @"GB", @"TB", @"PB" ];
    
    double totalSize = model.totalLength;
    NSInteger totalSizeUnitIndex = 0;
    while (totalSize >= 1024 && totalSizeUnitIndex < byteUnits.count) {
        totalSize /= 1024;
        totalSizeUnitIndex++;
    }
    
    self.textLabel.text = model.videoFileName;
    
    self.detailTextLabel.text = [NSString stringWithFormat:@"%dF"
                                 " %.2f%@"
                                 " %.1f%%"
                                 " %@",
                                 model.downloadFileType == PMDownloadFileType_Playback ? 3 : 2,
                                 totalSize, byteUnits[totalSizeUnitIndex],
                                 progress * 100,
                                 migrated ? @"♻️" : [self stringFromModelState:model.state]];
    
    [self.progressView bjl_updateConstraints:^(BJLConstraintMaker *make) {
        [self.progressViewWidthConstraint uninstall];
        self.progressViewWidthConstraint =
        make.width.equal.to(self.bjl_safeAreaLayoutGuide).multipliedBy(1.0 - progress).constraint;
    }];
    
    self.imageView.contentMode = UIViewContentModeScaleAspectFill;
    self.imageView.clipsToBounds = YES;
    self.imageView.image = (model.imagePath
                            ? [UIImage imageWithContentsOfFile:model.imagePath]
                            : nil);
    if (!self.imageView.image && model.imageUrl) {
        [self.imageView bjl_setImageWithURL:[NSURL URLWithString:model.imageUrl]
                                placeholder:[UIImage bjl_imageWithColor:[UIColor grayColor]]
                                 completion:nil];
    }
}

- (NSString *)stringFromModelState:(PMDownloadState)state {
    switch (state) {
        case PMDownloadState_Start:
            return @"⏸";
        case PMDownloadState_Suspended:
            return @"▶️";
        case PMDownloadState_Completed:
            return @"✅";
        case PMDownloadState_Failed:
            return @"❎";
        default: // PMDownloadState_Cancel
            return @"❌";
    }
}

@end

@interface BJVDownloadViewController () <BJLDownloadManagerDelegate>

@property (nonatomic) BJVDownloadManager *downloadManager;

@property (nonatomic, nullable) NSTimer *progressTimer;

@end

@implementation BJVDownloadViewController

/*
- (instancetype)initWithStyle:(UITableViewStyle)style {
    self = [super initWithStyle:style];
    if (self) {
    }
    return self;
} */

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    BJLYYFPSLabel *fpsLabel = [BJLYYFPSLabel new];
    [self.view addSubview:fpsLabel];
    [fpsLabel bjl_makeConstraints:^(BJLConstraintMaker *make) {
        make.left.equal.to(self.view).inset(5.0);
        make.top.equal.to(self.bjl_topLayoutGuide).offset(5.0);
    }];
    
    self.tableView.rowHeight = rowHeight;
    self.tableView.separatorInset = UIEdgeInsetsMake(0.0, imageSize + margin * 4, 0.0, 0.0);
    self.tableView.tableFooterView = [UIView new];
    
    [self.tableView registerClass:[BJVDownloadItemCell class] forCellReuseIdentifier:@"uncompleted"];
    [self.tableView registerClass:[BJVDownloadItemCell class] forCellReuseIdentifier:@"completed"];
    [self.tableView registerClass:[BJVDownloadItemCell class] forCellReuseIdentifier:@"pm-uncompleted"];
    [self.tableView registerClass:[BJVDownloadItemCell class] forCellReuseIdentifier:@"pm-completed"];
    
    [self makeBarButtons];
    
    if (!self.downloadManager) {
        self.downloadManager = [BJVDownloadManager downloadManagerWithIdentifier:@"self.manager"];
        self.downloadManager.delegate = self;
    }
    
    bjl_weakify(self);
    self.progressTimer = [NSTimer bjl_scheduledTimerWithTimeInterval:0.1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        bjl_strongify_ifNil(self) {
            [timer invalidate]; // or invalidate in dealloc
            return;
        }
        if (!self.isViewLoaded || !self.view.window) {
            return;
        }
        NSArray<NSIndexPath *> *indexPaths = [self.tableView indexPathsForVisibleRows];
        for (NSIndexPath *indexPath in indexPaths) {
            if (indexPath.section > 0) continue;
            BJVDownloadItem *item = [self.downloadManager.downloadItems bjl_objectAtIndex:indexPath.row];
            if (item.state == BJLDownloadItemState_running) {
                BJVDownloadItemCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
                [cell tryToUpdateWithItem:item];
            }
        }
    }];
    [[NSRunLoop currentRunLoop] addTimer:self.progressTimer forMode:NSRunLoopCommonModes];
}

- (void)makeBarButtons {
    bjl_weakify(self);
    
    UIBarButtonItem *addBarButtonItem = [UIBarButtonItem bjl_barButtonSystemItem:UIBarButtonSystemItemAdd];
    [addBarButtonItem bjl_addHandler:^(__kindof UIBarButtonItem * _Nullable sender) {
        bjl_strongify(self);
        UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:@"add" message:@"add video or playback" preferredStyle:UIAlertControllerStyleActionSheet];
        [actionSheet bjl_addActionWithTitle:@"添加点播下载" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [self addVideo];
        }];
        [actionSheet bjl_addActionWithTitle:@"添加回放下载" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [self addPlayback];
        }];
        [actionSheet bjl_addActionWithTitle:@"添加自定义下载" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [self addDownload];
        }];
        [actionSheet bjl_addActionWithTitle:@"crash!" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
            exit(0);
        }];
        [actionSheet bjl_addActionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:nil];
        actionSheet.popoverPresentationController.barButtonItem = sender;
        [self presentViewController:actionSheet animated:YES completion:nil];
    }];
    
    UIBarButtonItem *resumeBarButtonItem = [UIBarButtonItem bjl_barButtonSystemItem:UIBarButtonSystemItemPlay];
    [resumeBarButtonItem bjl_addHandler:^(__kindof UIBarButtonItem * _Nullable sender) {
        bjl_strongify(self);
        NSArray<BJVDownloadItem *> *items = [self.downloadManager downloadItemsWithStates:BJLDownloadItemState_paused, NSNotFound];
        [items makeObjectsPerformSelector:@selector(resume)];
    }];
    
    UIBarButtonItem *suspendBarButtonItem = [UIBarButtonItem bjl_barButtonSystemItem:UIBarButtonSystemItemPause];
    [suspendBarButtonItem bjl_addHandler:^(__kindof UIBarButtonItem * _Nullable sender) {
        bjl_strongify(self);
        NSArray<BJVDownloadItem *> *items = [self.downloadManager downloadItemsWithStates:BJLDownloadItemState_running, NSNotFound];
        [items makeObjectsPerformSelector:@selector(pause)];
    }];
    
    UIBarButtonItem *refreshBarButtonItem = [UIBarButtonItem bjl_barButtonSystemItem:UIBarButtonSystemItemRefresh];
    [refreshBarButtonItem bjl_addHandler:^(__kindof UIBarButtonItem * _Nullable sender) {
        bjl_strongify(self);
        [self.downloadManager refreshURLSessionWithCompletion:^(BJLDownloadManager * _Nonnull downloadManager) {
            [self showHUDWithMessage:@"NSURLSession 已刷新"];
        }];
    }];
    
    UIBarButtonItem *deleteBarButtonItem = [UIBarButtonItem bjl_barButtonSystemItem:UIBarButtonSystemItemTrash];
    [deleteBarButtonItem bjl_addHandler:^(__kindof UIBarButtonItem * _Nullable sender) {
        bjl_strongify(self);
        UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:@"delete all" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
        [actionSheet bjl_addActionWithTitle:@"delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
            for (BJVDownloadItem *item in self.downloadManager.downloadItems) {
                [self.downloadManager removeDownloadItemWithIdentifier:item.itemIdentifier];
            }
            [self.tableView reloadData];
        }];
        [actionSheet bjl_addActionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:nil];
        actionSheet.popoverPresentationController.barButtonItem = sender;
        [self presentViewController:actionSheet animated:YES completion:nil];
    }];
    
    self.navigationItem.rightBarButtonItems = @[ addBarButtonItem,
                                                 resumeBarButtonItem,
                                                 suspendBarButtonItem,
                                                 refreshBarButtonItem,
                                                 deleteBarButtonItem ];
}

- (void)addVideo {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"add" message:@"add video with index" preferredStyle:UIAlertControllerStyleAlert];
    
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.clearButtonMode = UITextFieldViewModeWhileEditing;
        textField.keyboardType = UIKeyboardTypeDecimalPad;
        // textField.returnKeyType = UIReturnKeyDone;
        textField.placeholder = [NSString stringWithFormat:@"index: 0.1.2... [0 - %tu]", BJLDownloadVideoTokens().count - 1];
    }];
    
    [alert bjl_addActionWithTitle:@"add" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        NSString *indexes = alert.textFields.firstObject.text;
        if (indexes.length) {
            for (NSString *index in [indexes componentsSeparatedByString:@"."]) {
                NSString *key = [BJLDownloadVideoTokens().allKeys bjl_objectAtIndex:index.integerValue];
                if (!key) {
                    [BJLProgressHUD bjl_showHUDForText:[NSString stringWithFormat:@"no video at index: %@", index] superview:self.view animated:YES];
                    continue;
                }
                [self addVideoWithKey:key];
            }
        }
        else {
            for (NSString *videoID in BJLDownloadVideoTokens().allKeys) {
                [self addVideoWithKey:videoID];
            }
        }
        [self.tableView reloadData];
    }];
    
    [alert bjl_addActionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:nil];
    
    [self presentViewController:alert animated:YES completion:nil];
}

- (void)addVideoWithKey:(NSString *)key {
    if (![self.downloadManager validateItemWithVideoID:key]) {
        [BJLProgressHUD bjl_showHUDForText:[NSString stringWithFormat:@"video existed: videoID %@", key] superview:self.view animated:YES];
        return;
    }
    id<BJVRequestTokenDelegate> appDelegate = (id<BJVRequestTokenDelegate>)[UIApplication sharedApplication].delegate;
    [BJVideoPlayerCore setTokenDelegate:appDelegate];
    BJVDownloadItem *item = [self.downloadManager addDownloadItemWithVideoID:key
                                                           encrypted:[PUPlayOptionsManager getVideoOptions].encryptEnabled
                                             preferredDefinitionList:[PUPlayOptionsManager getVideoOptions].preferredDefinitionList];
    NSLog(@"add video: %@", item);
}

- (void)addPlayback {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"add" message:@"add playback with index" preferredStyle:UIAlertControllerStyleAlert];
    
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.clearButtonMode = UITextFieldViewModeWhileEditing;
        textField.keyboardType = UIKeyboardTypeDecimalPad;
        // textField.returnKeyType = UIReturnKeyDone;
        textField.placeholder = [NSString stringWithFormat:@"index: 0.1.2... [0 - %tu]", BJLDownloadPlaybackTokens().count - 1];
    }];
    
    [alert bjl_addActionWithTitle:@"add" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        NSString *indexes = alert.textFields.firstObject.text;
        if (indexes.length) {
            for (NSString *index in [indexes componentsSeparatedByString:@"."]) {
                NSString *key = [BJLDownloadPlaybackTokens().allKeys bjl_objectAtIndex:index.integerValue];
                if (!key.length) {
                    [BJLProgressHUD bjl_showHUDForText:[NSString stringWithFormat:@"no playback at index: %@", index] superview:self.view animated:YES];
                    continue;
                }
                [self addPlaybackWithKey:key];
            }
        }
        else {
            for (NSString *key in BJLDownloadPlaybackTokens().allKeys) {
                [self addPlaybackWithKey:key];
            }
        }
        [self.tableView reloadData];
    }];
    
    [alert bjl_addActionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:nil];
    
    [self presentViewController:alert animated:YES completion:nil];
}

- (void)addPlaybackWithKey:(NSString *)key {
    NSArray<NSString *> *ids = [key componentsSeparatedByString:@"-"];
    NSString *classID = [ids bjl_objectAtIndex:0], *sessionID = [ids bjl_objectAtIndex:1];
    if (![self.downloadManager validateItemWithClassID:classID sessionID:sessionID]) {
        [BJLProgressHUD bjl_showHUDForText:[NSString stringWithFormat:@"playback existed: %@-%@", classID, sessionID] superview:self.view animated:YES];
        return;
    }
    id<BJVRequestTokenDelegate> appDelegate = (id<BJVRequestTokenDelegate>)[UIApplication sharedApplication].delegate;
    [BJVideoPlayerCore setTokenDelegate:appDelegate];
    BJVDownloadItem *item = [self.downloadManager addDownloadItemWithClassID:classID
                                                           sessionID:sessionID
                                                           encrypted:[PUPlayOptionsManager getPlaybackOptions].encryptEnabled
                                             preferredDefinitionList:[PUPlayOptionsManager getPlaybackOptions].preferredDefinitionList];
    NSLog(@"add playback: %@", item);
}

- (void)addDownload {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"添加下载" message:@"添加任意点播或者回放下载" preferredStyle:UIAlertControllerStyleAlert];
    
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.clearButtonMode = UITextFieldViewModeWhileEditing;
        textField.keyboardType = UIKeyboardTypeDecimalPad;
        textField.placeholder = @"点播或者回放ID";
        textField.text = @"412725";
    }];
    
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.clearButtonMode = UITextFieldViewModeWhileEditing;
        textField.keyboardType = UIKeyboardTypeDecimalPad;
        textField.placeholder = @"回放 sessionID";
    }];
    
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.clearButtonMode = UITextFieldViewModeWhileEditing;
        textField.keyboardType = UIKeyboardTypeDefault;
        textField.placeholder = @"点播或者回放 token";
        textField.text = @"Xp4A6rLuppba5pEg8imbnT9euaJfUWpmO7SkzU5osEJ8YSQXs9Jt5g";
    }];
    
    [alert bjl_addActionWithTitle:@"点播下载" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        NSString *videoID = alert.textFields.firstObject.text;
        NSString *token = alert.textFields.lastObject.text;
        if (![self.downloadManager validateItemWithVideoID:videoID]) {
            [BJLProgressHUD bjl_showHUDForText:[NSString stringWithFormat:@"要添加的点播已经存在 %@", videoID] superview:self.view animated:YES];
        }
        else {
            [BJVideoPlayerCore setTokenDelegate:nil];
            [self.downloadManager addDownloadItemWithVideoID:videoID encrypted:[PUPlayOptionsManager getVideoOptions].encryptEnabled preferredDefinitionList:[PUPlayOptionsManager getVideoOptions].preferredDefinitionList setting:^(BJVDownloadItem * _Nonnull item) {
                item.token = token;
            }];
        }
        [self.tableView reloadData];
    }];
    
    [alert bjl_addActionWithTitle:@"回放下载" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        NSString *classID = alert.textFields.firstObject.text;
        NSString *seesionID = [alert.textFields bjl_objectAtIndex:1].text;
        NSString *token = alert.textFields.lastObject.text;
        if (![self.downloadManager validateItemWithClassID:classID sessionID:seesionID]) {
            [BJLProgressHUD bjl_showHUDForText:[NSString stringWithFormat:@"要添加的回放已经存在 %@ %@", classID, seesionID] superview:self.view animated:YES];
        }
        else {
            [BJVideoPlayerCore setTokenDelegate:nil];
            [self.downloadManager addDownloadItemWithClassID:classID sessionID:seesionID encrypted:[PUPlayOptionsManager getPlaybackOptions].encryptEnabled preferredDefinitionList:[PUPlayOptionsManager getVideoOptions].preferredDefinitionList setting:^(BJVDownloadItem * _Nonnull item) {
                item.token = token;
            }];
        }
        [self.tableView reloadData];
    }];
    
    [alert bjl_addActionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:nil];
    
    [self presentViewController:alert animated:YES completion:nil];
}

#pragma mark - actions

- (void)playWithDownloadItem:(BJVDownloadItem *)item playerType:(BJVPlayerType)playerType {
    if (item.isPlayback) {
        BJPPlaybackOptions *playbackOptions = [PUPlayOptionsManager getPlaybackOptions];
        playbackOptions.playerType = playerType;
        [PUPlayOptionsManager setPlaybackOptions:playbackOptions];
        BJPRoomViewController *playbackVC = [BJPRoomViewController localPlaybackRoomWithDownloadItem:item
                                                                                             options:playbackOptions];
        [self bjl_presentFullScreenViewController:playbackVC animated:YES completion:nil];
    }
    else {
        BJPUVideoOptions *videoOptions = [PUPlayOptionsManager getVideoOptions];
        videoOptions.playerType = playerType;
        [PUPlayOptionsManager setVideoOptions:videoOptions];
        PMLocalViewViewController *localVideoVC = [[PMLocalViewViewController alloc] initWithDownloadItem:item
                                                                                                  options:videoOptions];
        [self.navigationController pushViewController:localVideoVC animated:YES];
    }
}

- (void)showHUDWithMessage:(NSString *)message {
    BJLProgressHUD *hud = [BJLProgressHUD showHUDAddedTo:self.view animated:YES];
    hud.mode = BJLMBProgressHUDModeText;
    hud.userInteractionEnabled = NO;
    hud.detailsLabel.text = message;
    [hud hideAnimated:YES afterDelay:3.0];
}

#pragma mark - <BJLDownloadManagerDelegate>

- (void)downloadManager:(BJVDownloadManager *)downloadManager
           downloadItem:(BJVDownloadItem *)downloadItem
              didChange:(BJLPropertyChange *)change {
    NSLog(@"downloadItem error %@ %td %f", downloadItem.error, downloadItem.state, downloadItem.progress.fractionCompleted);
    NSInteger index = [self.downloadManager.downloadItems indexOfObject:downloadItem];
    if (index == NSNotFound) {
        return;
    }
    
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
    BJVDownloadItemCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
    [cell updateWithItem:downloadItem];
}

#pragma mark - <UITableViewDataSource>

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 3;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    switch (section) {
        case 1: return @"1.0 下载中...";
        case 2: return @"1.0 下载完成";
        default: return @"2.0";
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    switch (section) {
        case 1: return [PMDownloadManager downloadManager].downloadingList.count;
        case 2: return [PMDownloadManager downloadManager].finishedList.count;
        default: return self.downloadManager.downloadItems.count;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section > 0) {
        PMDownloadModel *model = (indexPath.section == 1
                                  ? [[PMDownloadManager downloadManager].downloadingList bjl_objectAtIndex:indexPath.row]
                                  : [[PMDownloadManager downloadManager].finishedList bjl_objectAtIndex:indexPath.row]);
        BOOL completed = (model.state == PMDownloadState_Completed);
        
        BOOL migrated = (model.downloadFileType == PMDownloadFileType_Video
                         ? model.vid.length && ![self.downloadManager validateItemWithVideoID:model.vid]
                         : model.classId.length && ![self.downloadManager validateItemWithClassID:model.classId sessionID:model.sessionId]);
        
        BJVDownloadItemCell *cell = [tableView dequeueReusableCellWithIdentifier:completed ? @"pm-completed" : @"pm-uncompleted" forIndexPath:indexPath];
        [cell updateWithModel:model migrated:migrated];
        
        return cell;
    }
    
    BJVDownloadItem *item = [self.downloadManager.downloadItems bjl_objectAtIndex:indexPath.row];
    BOOL completed = (item.state == BJLDownloadItemState_completed);
    
    BJVDownloadItemCell *cell = [tableView dequeueReusableCellWithIdentifier:completed ? @"completed" : @"uncompleted" forIndexPath:indexPath];
    [cell updateWithItem:item];
    
    bjl_weakify(self);
    cell.updatePriority = cell.updatePriority ?: ^(float priority, BJVDownloadItemCell *cell) {
        bjl_strongify(self);
        NSIndexPath *indexPath = [tableView indexPathForCell:cell];
        BJVDownloadItem *item = [self.downloadManager.downloadItems bjl_objectAtIndex:indexPath.row];
        item.priority = priority;
    };
    
    return cell;
}

- (void)migrateDownloadModel:(PMDownloadModel *)model {
    BOOL valid = (model.downloadFileType == PMDownloadFileType_Video
                  ? [self.downloadManager validateItemWithVideoID:model.vid]
                  : [self.downloadManager validateItemWithClassID:model.classId sessionID:model.sessionId]);
    if (!valid) {
        NSString *ID = (model.downloadFileType == PMDownloadFileType_Video
                        ? model.vid
                        : model.classId);
        [self showHUDWithMessage:(ID.length
                                  ? [NSString stringWithFormat:@"任务已存在，无法添加 - %@", model.videoFileName]
                                  : [NSString stringWithFormat:@"数据有误，无法添加 - %@", model.videoFileName])];
        return;
    }
    
    BOOL completed = (model.state == PMDownloadState_Completed);
    if (completed && !model.readyForMigration) {
        bjl_weakify(self);
        [model prepareForMigrationWithCompletion:^(NSError * _Nullable error) {
            bjl_strongify(self);
            if (error || !model.readyForMigration) {
                [self showHUDWithMessage:[NSString stringWithFormat:@"prepare error - %@: %@", model.videoFileName, error]];
            }
            else {
                [self migrateDownloadModel:model];
            }
        }];
        return;
    }
    
    BJVDownloadMigrationCode code = BJVDownloadMigrationCode_added;
    BJVDownloadItem *item = nil;
    
    if (!completed) {
        item = [self.downloadManager migratePMDownloadModel:model code:&code];
    }
    else {
        item = [self.downloadManager migrateCompletedPMDownloadModel:model code:&code];
    }
    
    if (item) {
        [self showHUDWithMessage:@"添加成功"];
        [self.tableView reloadData];
    }
    else {
        switch (code) {
            case BJVDownloadMigrationCode_ivalidPMDownloadModel:
                [self showHUDWithMessage:[NSString stringWithFormat:@"ivalidPMDownloadModel - %@", model.videoFileName]];
                break;
            case BJVDownloadMigrationCode_uncompletedPMDownloadModel:
                [self showHUDWithMessage:[NSString stringWithFormat:@"uncompletedPMDownloadModel - %@", model.videoFileName]];
                break;
            case BJVDownloadMigrationCode_fileLost:
                [self showHUDWithMessage:[NSString stringWithFormat:@"fileLost - %@", model.videoFileName]];
                break;
            case BJVDownloadMigrationCode_notReadyForMigration:
                [self showHUDWithMessage:[NSString stringWithFormat:@"notReadyForMigration - %@", model.videoFileName]];
                break;
            case BJVDownloadMigrationCode_failedWithError:
                [self showHUDWithMessage:[NSString stringWithFormat:@"failedWithError - %@", model.videoFileName]];
                break;
            default:
                [self showHUDWithMessage:[NSString stringWithFormat:@"unknownError - %@", model.videoFileName]];
                break;
        }
    }
}

#pragma mark - <UITableViewDelegate>

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    
    if (indexPath.section > 0) {
        
        PMDownloadModel *model = (indexPath.section == 1
                                  ? [[PMDownloadManager downloadManager].downloadingList bjl_objectAtIndex:indexPath.row]
                                  : [[PMDownloadManager downloadManager].finishedList bjl_objectAtIndex:indexPath.row]);
        [self migrateDownloadModel:model];
        return;
    }
    
    BJVDownloadItem *item = [self.downloadManager.downloadItems bjl_objectAtIndex:indexPath.row];
    if (item.state == BJLDownloadItemState_completed) {
        if (item.error) {
            [item resume];
        }
        else {
            bjl_weakify(self);
            UIAlertController *alertController = [UIAlertController
                                                  alertControllerWithTitle:@"选择播放器"
                                                  message:nil
                                                  preferredStyle:UIAlertControllerStyleActionSheet];
            
            [alertController addAction:[UIAlertAction actionWithTitle:@"AVPlayer"
                                                                style:UIAlertActionStyleDefault
                                                              handler:^(UIAlertAction *action) {
                                                                  bjl_strongify(self);
                                                                  [self playWithDownloadItem:item playerType:BJVPlayerType_AVPlayer];
                                                              }]];
            
            [alertController addAction:[UIAlertAction actionWithTitle:@"IJKPlayer"
                                                                style:UIAlertActionStyleDefault
                                                              handler:^(UIAlertAction *action) {
                                                                  bjl_strongify(self);
                                                                  [self playWithDownloadItem:item playerType:BJVPlayerType_IJKPlayer];
                                                              }]];
            
            
            [alertController addAction:[UIAlertAction actionWithTitle:@"取消"
                                                                style:UIAlertActionStyleCancel
                                                              handler:nil]];
            alertController.popoverPresentationController.sourceView = [self.tableView cellForRowAtIndexPath:indexPath] ?: self.view;
            alertController.popoverPresentationController.sourceRect = CGRectMake(20.0, 20.0, 0.0, 0.0);
            alertController.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionUp | UIPopoverArrowDirectionDown;
            [self presentViewController:alertController animated:YES completion:nil];
            [tableView deselectRowAtIndexPath:indexPath animated:YES];
        }
        return;
    }
    
    if (item.state == BJLDownloadItemState_running) {
        [item pause];
    }
    else {
        [item resume];
    }
}

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section > 0) {
        
        return;
    }
    
    BJVDownloadItem *item = [self.downloadManager.downloadItems bjl_objectAtIndex:indexPath.row];
    if (item.error) {
        [self showHUDWithMessage:[NSString stringWithFormat:@"错误:\n%@", item.error.localizedDescription]];
    }
    else if (item.state == BJLDownloadItemState_running
             || item.state == BJLDownloadItemState_paused) {
        [self showHUDWithMessage:BJLStringFromProgress(item.progress)];
    }
    else {
        [self showHUDWithMessage:@"无错误"];
    }
}

- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section > 0) {
        PMDownloadModel *model = (indexPath.section == 1
                                  ? [[PMDownloadManager downloadManager].downloadingList bjl_objectAtIndex:indexPath.row]
                                  : [[PMDownloadManager downloadManager].finishedList bjl_objectAtIndex:indexPath.row]);
        return @[[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"delete" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
            [[PMDownloadManager downloadManager] removePMDownloadModel:model];
            [self.tableView reloadData];
        }]];
    }
    
    BJVDownloadItem *item = [self.downloadManager.downloadItems bjl_objectAtIndex:indexPath.row];
    return @[[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"delete" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        [self.downloadManager removeDownloadItemWithIdentifier:item.itemIdentifier];
        [self.tableView reloadData];
    }]];
}

// for iOS 8
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { return UITableViewCellEditingStyleDelete; }
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { }

@end
