/*
 * Copyright [2019] [Doric.Pub]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//
//  DoricDevViewController.m
//  Doric
//
//  Created by jingpeng.wang on 2020/2/26.
//
#import <DoricCore/Doric.h>
#import <DoricCore/DoricContextManager.h>
#import<CommonCrypto/CommonDigest.h>

#import "DoricDev.h"
#import "DoricDevViewController.h"
#import "QRScanViewController.h"
#import "DoricDebugDriver.h"
#import "DoricSnapshotView.h"
#import "DoricShowNodeTreeViewController.h"
#import "DoricRegistry.h"
#import "DoricSnapshotView.h"
#import "DoricDevPerfVC.h"

@interface DoricContextCell : UITableViewCell
@property(nonatomic, strong) UILabel *tvId;
@property(nonatomic, strong) UILabel *tvSource;
@property(nonatomic, strong) UIView *vBtn;
@property(nonatomic, strong) UIImageView *ivDebug;
@property(nonatomic, weak) DoricContext *doricContext;
@property(nonatomic, weak) UIViewController *vc;
@end

@implementation DoricContextCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        self.tvId = [[UILabel new] also:^(UILabel *it) {
            it.width = 50;
            it.textAlignment = NSTextAlignmentCenter;
            it.font = [UIFont systemFontOfSize:20];
            it.textColor = [UIColor blackColor];
            it.left = 0;
            [self.contentView addSubview:it];
        }];
        self.tvSource = [[UILabel new] also:^(UILabel *it) {
            it.textAlignment = NSTextAlignmentCenter;
            it.font = [UIFont systemFontOfSize:20];
            it.textColor = [UIColor blackColor];
            [self.contentView addSubview:it];
        }];
        self.vBtn = [[UIView new] also:^(UIView *it) {
            it.width = 60;
            it.height = 60;
            [self.contentView addSubview:it];
            UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClick)];
            [it addGestureRecognizer:tapGestureRecognizer];
        }];
        self.ivDebug = [[UIImageView new] also:^(UIImageView *it) {
            it.width = 20;
            it.height = 20;
            it.centerX = self.vBtn.width / 2;
            it.centerY = self.vBtn.height / 2;
            it.contentMode = UIViewContentModeScaleToFill;
            [self.vBtn addSubview:it];
        }];
    }
    return self;
}

- (NSString *)md5:(NSString *)input {
    const char *cStr = [input UTF8String];
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, (CC_LONG) strlen(cStr), digest);

    NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [output appendFormat:@"%02x", digest[i]];
    }
    return output;

}

- (void)onClick {
    UIAlertController *alertController = [[UIAlertController alloc] init];
    UIAlertAction *cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];
    UIAlertAction *viewSource = [UIAlertAction actionWithTitle:@"View source" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_) {
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"View source: %@", self.doricContext.source]
                                                                       message:[NSString stringWithFormat:@"Size:%@\nMD5:%@\nScript:\n%@",
                                                                                                          @(self.doricContext.script.length),
                                                                                                          [self md5:self.doricContext.script],
                                                                                                          self.doricContext.script]
                                                                preferredStyle:
                                                                        UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
                                                         style:UIAlertActionStyleDefault
                                                       handler:nil];
        [alert addAction:action];
        [self.vc presentViewController:alert animated:YES completion:nil];
    }];
    [alertController addAction:cancel];
    [alertController addAction:viewSource];


    if (DoricDev.instance.isInDevMode) {
        if ([self.doricContext.driver isKindOfClass:DoricDebugDriver.class]) {
            UIAlertAction *stopDebugging = [UIAlertAction actionWithTitle:@"Stop debugging" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_) {
                [DoricDev.instance stopDebugging:YES];
            }];
            [alertController addAction:stopDebugging];
        } else {
            UIAlertAction *startDebugging = [UIAlertAction actionWithTitle:@"Start debugging" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_) {
                [DoricDev.instance requestDebugging:self.doricContext];
            }];
            [alertController addAction:startDebugging];
        }
    }
    if ([Doric isEnableRenderSnapshot]) {
        UIAlertAction *snapshot = [UIAlertAction actionWithTitle:@"Snapshot" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_) {
            DoricSnapshotView *doricSnapshotView = [[DoricSnapshotView alloc] initWithDoricContext:self.doricContext];
            doricSnapshotView.top = 50;
            [self.doricContext.vc.view addSubview:doricSnapshotView];
            [self.vc.navigationController popViewControllerAnimated:NO];
        }];
        [alertController addAction:snapshot];
    }

    if ([Doric isEnablePerformance]) {
        UIAlertAction *performanceAction = [UIAlertAction
                actionWithTitle:@"Performance"
                          style:UIAlertActionStyleDefault
                        handler:^(UIAlertAction *_) {
                            DoricDevPerfVC *doricDevPerfVc = [[DoricDevPerfVC alloc] initWithContextId:self.doricContext.contextId];
                            UIViewController *viewController = [UIApplication sharedApplication].delegate.window.rootViewController;
                            UINavigationController *navigationController;
                            if ([viewController isKindOfClass:[UINavigationController class]]) {
                                navigationController = (UINavigationController *) viewController;
                            } else {
                                navigationController = viewController.navigationController;
                            }
                            [navigationController pushViewController:doricDevPerfVc animated:NO];
                        }];
        [alertController addAction:performanceAction];
    }

    UIAlertAction *showNodeTree = [UIAlertAction actionWithTitle:@"View node tree" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_) {
        DoricShowNodeTreeViewController *doricShowNodeTreeViewController = [[DoricShowNodeTreeViewController alloc] init];
        doricShowNodeTreeViewController.contextId = self.doricContext.contextId;

        UIViewController *viewController = [UIApplication sharedApplication].delegate.window.rootViewController;
        UINavigationController *navigationController;
        if ([viewController isKindOfClass:[UINavigationController class]]) {
            navigationController = (UINavigationController *) viewController;
        } else {
            navigationController = viewController.navigationController;
        }
        [navigationController pushViewController:doricShowNodeTreeViewController animated:NO];
    }];
    [alertController addAction:showNodeTree];

    [self.vc presentViewController:alertController animated:true completion:nil];
}
@end

@interface DoricDevViewController () <UITableViewDelegate, UITableViewDataSource, DoricDevStatusCallback>
@property(nonatomic, strong) UIView *headerView;
@property(nonatomic, strong) UILabel *tvLabel;
@property(nonatomic, strong) UILabel *tvConnection;
@property(nonatomic, strong) UILabel *tvInput;
@property(nonatomic, strong) UILabel *tvScan;
@property(nonatomic, strong) UILabel *tvDisconnect;
@property(nonatomic, strong) UILabel *tvSnapshot;
@property(nonatomic, strong) UILabel *tvPerformance;
@property(nonatomic, strong) UISwitch *switchSnapshot;
@property(nonatomic, strong) UISwitch *switchPerformance;
@property(nonatomic, strong) UITableView *listView;

@end

@implementation DoricDevViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"Doric Devkit";
    self.edgesForExtendedLayout = UIRectEdgeNone;
    self.view.backgroundColor = UIColor.whiteColor;
    self.headerView = [[UIView new] also:^(UIView *it) {
        it.width = self.view.width;
        it.height = 140;
        it.backgroundColor = DoricColor(@(0xff70a1ff));
        [self.view addSubview:it];
    }];
    self.tvLabel = [[UILabel new] also:^(UILabel *it) {
        it.text = @"Devkit";
        it.textColor = [UIColor whiteColor];
        it.font = [UIFont systemFontOfSize:30];
        it.textAlignment = NSTextAlignmentCenter;
        [it sizeToFit];
        it.centerY = self.headerView.centerY;
        it.left = 15;
        [self.headerView addSubview:it];
    }];
    self.tvConnection = [[UILabel new] also:^(UILabel *it) {
        it.text = @"Disconnected";
        it.textColor = [UIColor whiteColor];
        it.font = [UIFont systemFontOfSize:12];
        it.textAlignment = NSTextAlignmentCenter;
        [it sizeToFit];
        [self.headerView addSubview:it];
    }];
    self.tvInput = [[UILabel new] also:^(UILabel *it) {
        it.text = @"Input";
        it.textColor = [UIColor whiteColor];
        it.font = [UIFont systemFontOfSize:15];
        it.textAlignment = NSTextAlignmentCenter;
        [it sizeToFit];
        it.width += 30;
        it.height += 10;
        it.backgroundColor = DoricColor(@(0xff1abc9c));
        [self.headerView addSubview:it];
        it.userInteractionEnabled = YES;
        UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(input)];
        [it addGestureRecognizer:tapGestureRecognizer];
    }];
    self.tvScan = [[UILabel new] also:^(UILabel *it) {
        it.text = @"Scan";
        it.textColor = [UIColor whiteColor];
        it.font = [UIFont systemFontOfSize:15];
        it.textAlignment = NSTextAlignmentCenter;
        [it sizeToFit];
        it.width += 30;
        it.height += 10;
        it.backgroundColor = DoricColor(@(0xff1abc9c));
        [self.headerView addSubview:it];
        it.userInteractionEnabled = YES;
        UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scan)];
        [it addGestureRecognizer:tapGestureRecognizer];
    }];
    self.tvDisconnect = [[UILabel new] also:^(UILabel *it) {
        it.text = @"Disconnect";
        it.textColor = [UIColor whiteColor];
        it.font = [UIFont systemFontOfSize:15];
        it.textAlignment = NSTextAlignmentCenter;
        [it sizeToFit];
        it.width += 30;
        it.height += 10;
        it.backgroundColor = DoricColor(@(0xff95a5a6));
        [self.headerView addSubview:it];
        it.userInteractionEnabled = YES;
        UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(disconnect)];
        [it addGestureRecognizer:tapGestureRecognizer];
    }];
    self.tvSnapshot = [[UILabel new] also:^(UILabel *it) {
        it.text = @"Record Snapshot";
        it.textColor = [UIColor whiteColor];
        it.font = [UIFont systemFontOfSize:15];
        it.textAlignment = NSTextAlignmentCenter;
        [it sizeToFit];
        [self.headerView addSubview:it];
    }];
    self.tvPerformance = [[UILabel new] also:^(UILabel *it) {
        it.text = @"Performance";
        it.textColor = [UIColor whiteColor];
        it.font = [UIFont systemFontOfSize:15];
        it.textAlignment = NSTextAlignmentCenter;
        [it sizeToFit];
        [self.headerView addSubview:it];
    }];
    self.switchSnapshot = [[UISwitch new] also:^(UISwitch *it) {
        [it addTarget:self action:@selector(onSnapshotSwitch) forControlEvents:UIControlEventValueChanged];
        [self.headerView addSubview:it];
    }];
    self.switchPerformance = [[UISwitch new] also:^(UISwitch *it) {
        [it addTarget:self action:@selector(onPerformanceSwitch) forControlEvents:UIControlEventValueChanged];
        [self.headerView addSubview:it];
    }];
    [self initHeaders];
    [self initList];
    [DoricDev.instance addStatusCallback:self];
}

- (void)onSnapshotSwitch {
    [Doric enableRenderSnapshot:self.switchSnapshot.isOn];
}

- (void)onPerformanceSwitch {
    [Doric enablePerformance:self.switchPerformance.isOn];
}

- (void)disconnect {
    [DoricDev.instance closeDevMode];
}

- (void)input {
    if (self.isSimulator) {
        NSString *result = @"127.0.0.1";
        [[DoricDev instance] connectDevKit:[NSString stringWithFormat:@"ws://%@:7777", result]];
        ShowToast([NSString stringWithFormat:@"Connecting to %@", result], DoricGravityBottom);
    } else {
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Please input devkit ip"
                                                                       message:@""
                                                                preferredStyle:UIAlertControllerStyleAlert];
        [alert addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) {
            textField.placeholder = @"192.168.1.1";
            if (DoricDev.instance.ip) {
                textField.text = DoricDev.instance.ip;
            }
        }];
        __weak typeof(alert) _alert = alert;

        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil)
                                                               style:UIAlertActionStyleDefault
                                                             handler:nil];
        [alert addAction:cancelAction];

        UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Ok", nil)
                                                           style:UIAlertActionStyleDefault
                                                         handler:^(UIAlertAction *action) {
                                                             __strong typeof(_alert) alert = _alert;
                                                             NSString *ip = alert.textFields.lastObject.text;
                                                             [[DoricDev instance] connectDevKit:[NSString stringWithFormat:@"ws://%@:7777", ip]];
                                                         }];
        [alert addAction:okAction];

        [self presentViewController:alert animated:YES completion:nil];
    }
}

- (void)scan {
    if (self.isSimulator) {
        NSString *result = @"127.0.0.1";
        [[DoricDev instance] connectDevKit:[NSString stringWithFormat:@"ws://%@:7777", result]];
        ShowToast([NSString stringWithFormat:@"Connected to %@", result], DoricGravityBottom);
    } else {
        [self.navigationController pushViewController:[QRScanViewController new] animated:NO];
    }
}

- (void)initHeaders {
    if (DoricDev.instance.isInDevMode) {
        self.tvConnection.text = DoricDev.instance.ip;
        self.tvInput.hidden = YES;
        self.tvScan.hidden = YES;
        self.tvDisconnect.hidden = NO;
        self.tvConnection.backgroundColor = DoricColor(@(0xff2ed573));

        [self.tvConnection sizeToFit];
        self.tvConnection.width += 20;
        self.tvConnection.height += 6;

        self.tvConnection.left = self.tvLabel.right + 20;
        self.tvDisconnect.right = self.view.width - 15;
        self.tvConnection.top = 15;
        self.tvDisconnect.top = 15;
    } else {
        self.tvConnection.text = @"Disconnected";
        self.tvInput.hidden = NO;
        self.tvScan.hidden = NO;
        self.tvDisconnect.hidden = YES;
        self.tvConnection.backgroundColor = DoricColor(@(0xffa4b0be));

        [self.tvConnection sizeToFit];
        self.tvConnection.width += 20;
        self.tvConnection.height += 6;

        self.tvConnection.left = self.tvLabel.right + 20;
        self.tvScan.right = self.view.width - 15;
        self.tvInput.right = self.tvScan.left - 10;

        self.tvConnection.top = 15;
        self.tvScan.top = 15;
        self.tvInput.top = 15;
    }
    self.tvSnapshot.left = self.tvLabel.right + 20;
    self.switchSnapshot.left = self.tvSnapshot.right + 20;
    self.switchSnapshot.top = self.tvConnection.bottom + 15;
    self.tvSnapshot.centerY = self.switchSnapshot.centerY;
    self.switchSnapshot.on = [Doric isEnableRenderSnapshot];

    self.tvPerformance.left = self.tvLabel.right + 20;
    self.switchPerformance.left = self.tvPerformance.right + 20;
    self.switchPerformance.top = self.switchSnapshot.bottom + 15;
    self.tvPerformance.centerY = self.switchPerformance.centerY;
    self.switchPerformance.on = [Doric isEnablePerformance];
}

- (void)initList {
    self.listView = [[UITableView new] also:^(UITableView *it) {
        it.width = self.view.width;
        it.height = self.view.height - self.headerView.height;
        it.top = self.headerView.height;
        it.backgroundColor = DoricColor(@(0xffdfe6e9));
        [self.view addSubview:it];
        it.delegate = self;
        it.dataSource = self;
        [it setSeparatorStyle:UITableViewCellSeparatorStyleNone];
    }];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.listView.height = self.view.height - self.headerView.height;
}

- (UIImage *)decodeImage:(BOOL)on {
    NSString *debugOff = @" ";
    NSString *debugOn = @" ";
    NSString *base64 = on ? debugOn : debugOff;
    NSData *imageData = [[NSData alloc] initWithBase64EncodedString:base64
                                                            options:NSDataBase64DecodingIgnoreUnknownCharacters];
    return [UIImage imageWithData:imageData];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
        (NSInteger)section {
    return [DoricContextManager.instance aliveContexts].count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    DoricContextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (cell == nil) {
        cell = [[DoricContextCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }
    DoricContext *context = [DoricContextManager.instance aliveContexts][(NSUInteger) indexPath.row];
    NSString *contextId = context.contextId;
    NSString *source = context.source;
    cell.doricContext = context;
    cell.contentView.width = tableView.width;
    cell.contentView.height = 60;
    cell.tvId.text = contextId;
    cell.tvSource.text = source;
    cell.ivDebug.image = [self decodeImage:DoricDev.instance.isInDevMode];
    [cell.tvId sizeToFit];
    [cell.tvSource sizeToFit];
    cell.tvId.centerY = cell.contentView.height / 2;
    cell.tvId.width = 50;
    cell.tvSource.centerY = cell.contentView.height / 2;
    cell.vBtn.centerY = cell.contentView.height / 2;
    cell.tvSource.width = cell.contentView.width - cell.tvId.width - cell.vBtn.width;
    cell.tvId.left = 0;
    cell.tvSource.left = cell.tvId.right;
    cell.vBtn.right = cell.contentView.width;
    cell.vc = self;
    cell.contentView.backgroundColor = indexPath.row % 2 == 0 ? DoricColor(@(0xffecf0f1)) : DoricColor(@(0xffbdc3c7));
    if ([DoricDev.instance isReloadingContext:context]) {
        cell.contentView.backgroundColor = DoricColor(@(0xffffeaa7));
    }
    if ([context.driver isKindOfClass:DoricDebugDriver.class]) {
        cell.contentView.backgroundColor = DoricColor(@(0xfffab1a0));
    }
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 60.f;
}

- (BOOL)isSimulator {
    return TARGET_OS_SIMULATOR == 1;
}


- (void)onOpen:(NSString *)url {
    [self initHeaders];
    [self.listView reloadData];
}

- (void)onClose:(NSString *)url {
    [self initHeaders];
    [self.listView reloadData];
}

- (void)onFailure:(NSError *)error {
    [self initHeaders];
    [self.listView reloadData];
}

- (void)onReload:(DoricContext *)context
          script:
                  (NSString *)script {
    [self.listView reloadData];
}

- (void)onStartDebugging:(DoricContext *)context {
    [self.listView reloadData];
}

- (void)onStopDebugging {
    [self.listView reloadData];
}


@end
