//
//  Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//

#import "OWSQRCodeScanningViewController.h"
#import "OWSBezierPathView.h"
#import "UIColor+OWS.h"
#import "UIView+OWS.h"

NS_ASSUME_NONNULL_BEGIN

@interface OWSQRCodeScanningViewController ()

@property (atomic) ZXCapture *capture;
@property (nonatomic) BOOL captureEnabled;
@property (nonatomic) UIView *maskingView;
@property (nonatomic) dispatch_queue_t captureQueue;

@end

#pragma mark -

@implementation OWSQRCodeScanningViewController

- (void)dealloc
{
    [self.capture.layer removeFromSuperlayer];
}

- (instancetype)init
{
    self = [super init];
    if (!self) {
        return self;
    }

    _captureEnabled = NO;
    _captureQueue = dispatch_get_main_queue();

    return self;
}

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

    _captureEnabled = NO;
    _captureQueue = dispatch_get_main_queue();

    return self;
}

- (void)loadView
{
    [super loadView];

    OWSBezierPathView *maskingView = [OWSBezierPathView new];
    self.maskingView = maskingView;
    [maskingView setConfigureShapeLayerBlock:^(CAShapeLayer *layer, CGRect bounds) {
        // Add a circular mask
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:bounds];
        CGFloat margin = ScaleFromIPhone5To7Plus(24.f, 48.f);
        CGFloat radius = MIN(bounds.size.width, bounds.size.height) * 0.5f - margin;

        // Center the circle's bounding rectangle
        CGRect circleRect = CGRectMake(
            bounds.size.width * 0.5f - radius, bounds.size.height * 0.5f - radius, radius * 2.f, radius * 2.f);
        UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:circleRect cornerRadius:16.f];
        [path appendPath:circlePath];
        [path setUsesEvenOddFillRule:YES];

        layer.path = path.CGPath;
        layer.fillRule = kCAFillRuleEvenOdd;
        layer.fillColor = UIColor.lokiDarkestGray.CGColor;
        layer.opacity = 0.32f;
    }];
    [self.view addSubview:maskingView];
    [maskingView ows_autoPinToSuperviewEdges];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if (self.captureEnabled) {
        [self startCapture];
    }
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self stopCapture];
}

- (void)viewWillLayoutSubviews
{
    self.capture.layer.frame = self.view.bounds;
}

- (void)startCapture
{
    self.captureEnabled = YES;
    if (!self.capture) {
        dispatch_async(self.captureQueue, ^{
            self.capture = [[ZXCapture alloc] init];
            self.capture.camera = self.capture.back;
            self.capture.focusMode = AVCaptureFocusModeContinuousAutoFocus;
            self.capture.delegate = self;

            dispatch_async(dispatch_get_main_queue(), ^{
                self.capture.layer.frame = self.view.bounds;
                [self.view.layer addSublayer:self.capture.layer];
                [self.view bringSubviewToFront:self.maskingView];
                [self.capture start];
            });
        });
    } else {
        [self.capture start];
    }
}

- (void)stopCapture
{
    self.captureEnabled = NO;
    dispatch_async(self.captureQueue, ^{
        [self.capture stop];
    });
}

- (void)captureResult:(ZXCapture *)capture result:(ZXResult *)result
{
    if (!self.captureEnabled) {
        return;
    }
    [self stopCapture];

    // Vibrate
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

    if (self.scanDelegate) {
        if ([self.scanDelegate respondsToSelector:@selector(controller:didDetectQRCodeWithData:)]) {
            OWSLogInfo(@"Scanned Data Code.");
            ZXByteArray *byteArray = result.resultMetadata[@(kResultMetadataTypeByteSegments)][0];
            NSData *decodedData = [NSData dataWithBytes:byteArray.array length:byteArray.length];

            [self.scanDelegate controller:self didDetectQRCodeWithData:decodedData];
        }

        if ([self.scanDelegate respondsToSelector:@selector(controller:didDetectQRCodeWithString:)]) {
            OWSLogInfo(@"Scanned String Code.");
            [self.scanDelegate controller:self didDetectQRCodeWithString:result.text];
        }
    }
}

@end

NS_ASSUME_NONNULL_END