//
// CheckInScanViewController.m
// GoToBus
//
// Created by iphone development on 3/6/13.
// Copyright 2013 __MyCompanyName__. All rights reserved.
//

#import "CheckInScanViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "Lang.h"
#import "SDK.h"
#import "CocoaUtils.h"
#import <BlocksKit/BlocksKit.h>
#import <BlocksKit/BlocksKit+UIKit.h>
#import <libextobjc/EXTScope.h>
#import "Utility.h"
#import "PurchaseRecordResponseJsonMapper.h"
#import "QuickScanTicketResponseJsonMapper.h"
#import "PerlWS.h"
#import "CheckInActionHandler.h"
#import "CheckInResultViewController.h"
#import "Vars.h"

@interface CheckInScanViewController () <AVCaptureMetadataOutputObjectsDelegate>

@property (nonatomic, weak) IBOutlet UILabel *tooltipLabel;
@property (nonatomic, weak) IBOutlet UIView *scanRectView;


@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) dispatch_queue_t sessionQueue;

@property (nonatomic, strong) NSMutableArray *stocks;
@property (nonatomic, strong) NSString *qrCode;

@end

@implementation CheckInScanViewController

- (instancetype)init {
	if (self = [super init]) {
		// Custom initialization
		self.edgesForExtendedLayout = UIRectEdgeNone;
		self.title = @"Check-In";
		self.hidesBottomBarWhenPushed = YES;
		[[Vars appDelegate] applyDefaultConfigurationForViewController:self];
	}
	return self;
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
	[super viewDidLoad];

	self.stocks = [NSMutableArray array];

	self.tooltipLabel.text = [NSString stringWithFormat:@"Place a %@ inside the viewfinder rectangle to scan it", [[Vars appDelegate].loginUser.availableMetadataObjectType isEqualToString:AVMetadataObjectTypeQRCode] ? @"QR code" : @"barcode"];

	[self createReading];
}

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

	[self beginReading];
}

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

	[self stopReading];
}

#pragma mark - Network

- (void)quickScanTicket {
	QuickScanTicket *quickScanTicket = [[QuickScanTicket alloc] init];
	quickScanTicket.qrCode = self.qrCode;
	quickScanTicket.autoCheckin = YES;
	quickScanTicket.productNo = self.product_id;
	quickScanTicket.departureDate = self.service_date;

	NSDictionary *requestDict = [Utility perlParamXml:[quickScanTicket innerXML] action:quickScanTicket.name];

	[Utility getXMLFromRequestWithMethod:@"GET" url:quickScanTicket.address parameters:requestDict success:^(NSString *xml) {
		NSString *responseStr = xml;

		QuickScanTicketResponseJsonMapper *mapper = [[QuickScanTicketResponseJsonMapper alloc] init];
		NSDictionary *jsonDict = [Utility JSONObjectWithXMLString:responseStr objectMapping:mapper.objectMapping];
		if (![mapper parseWithJSONObject:jsonDict]) {
			QuickScanTicketResponse *response = mapper.response;
			if (response.error_code > 0) {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:response.error_message dismissalHandler:^{
					[self beginReading];
				}];
			} else {
				SoldStock *stock = response.sold_stock;
				TicketStatus tStatus = [self lookupTicketStatus:stock];
				if (tStatus != TicketStatusInvalid) {
					[self.stocks addObject:stock];
				}
				[self showResult:stock];
			}
		} else {
			[self beginReading];
		}
	} error:^(NSError *error) {
		[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:error.localizedDescription dismissalHandler:^{
			[self beginReading];
		}];
	}];
}

#pragma mark - Private

- (void)createReading {
	if (TARGET_IPHONE_SIMULATOR) {
		return;
	}
	self.sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL);
	@weakify(self)
	dispatch_async(self.sessionQueue, ^{
		// NSLog(@"create %@ %@", [NSThread currentThread], [NSOperationQueue currentQueue]);
		@strongify(self)
		AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
		if (captureDevice.isAutoFocusRangeRestrictionSupported) {
			if ([captureDevice lockForConfiguration:NULL]) {
				captureDevice.autoFocusRangeRestriction = AVCaptureAutoFocusRangeRestrictionNear;
				[captureDevice unlockForConfiguration];
			}
		}
		AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:NULL];
		if (!input) {
			return;
		}
		self.captureSession = [[AVCaptureSession alloc] init];
		if (![self.captureSession canAddInput:input]) {
			return;
		}
		[self.captureSession addInput:input];

		AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
		[captureMetadataOutput setMetadataObjectsDelegate:self queue:self.sessionQueue];
		if (![self.captureSession canAddOutput:captureMetadataOutput]) {
			return;
		}
		[self.captureSession addOutput:captureMetadataOutput];
		captureMetadataOutput.metadataObjectTypes = @[[Vars appDelegate].loginUser.availableMetadataObjectType];
	});
}

- (void)beginReading {
	self.qrCode = nil;
	for (SoldStock *stock in self.stocks) {
		stock.checked = NO;
	}
	if (TARGET_IPHONE_SIMULATOR) {
		[CocoaUtils showPlainInputBoxWithTitle:@"QR Code" message:nil configurationHandler:nil dismissalHandler:^(UITextField *textField) {
			self.qrCode = textField.text;
			[self postScan];
		}];
		return;
	}
	@weakify(self)
	dispatch_async(self.sessionQueue, ^{
		// NSLog(@"start %@ %@", [NSThread currentThread], [NSOperationQueue currentQueue]);
		@strongify(self)
		if (![self.captureSession isRunning]) {
			[self.captureSession startRunning];
		}
		dispatch_async(dispatch_get_main_queue(), ^{
			// NSLog(@"add layer %@ %@", [NSThread currentThread], [NSOperationQueue currentQueue]);
			AVCaptureVideoPreviewLayer *videoPreviewLayer = [CocoaUtils sublayerWithName:NSStringFromClass([AVCaptureVideoPreviewLayer class]) fromSuperlayer:self.scanRectView.layer];
			if (!videoPreviewLayer) {
				videoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
				videoPreviewLayer.name = NSStringFromClass([AVCaptureVideoPreviewLayer class]);
				[self.scanRectView.layer addSublayer:videoPreviewLayer];
			}
			videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
			videoPreviewLayer.frame = self.scanRectView.bounds;
		});
	});
}

- (void)stopReading {
	if (TARGET_IPHONE_SIMULATOR) {
		return;
	}
	@weakify(self)
	dispatch_async(self.sessionQueue, ^{
		// NSLog(@"stop %@ %@", [NSThread currentThread], [NSOperationQueue currentQueue]);
		@strongify(self)
		if ([self.captureSession isRunning]) {
			[self.captureSession stopRunning];
		}
		dispatch_async(dispatch_get_main_queue(), ^{
			// NSLog(@"remove layer %@ %@", [NSThread currentThread], [NSOperationQueue currentQueue]);
			AVCaptureVideoPreviewLayer *videoPreviewLayer = [CocoaUtils sublayerWithName:NSStringFromClass([AVCaptureVideoPreviewLayer class]) fromSuperlayer:self.scanRectView.layer];
			if (videoPreviewLayer) {
				[videoPreviewLayer removeFromSuperlayer];
			}
		});
	});
}

- (void)showResult:(SoldStock *)stock {
	CheckInResultViewController *viewController = [[CheckInResultViewController alloc] init];
	viewController.stock = stock;
	viewController.product_id = self.product_id;
	viewController.service_date = self.service_date;
	[self.navigationController pushViewController:viewController animated:YES];
}

- (void)postScan {
	SoldStock *stock = [self lookupStock:self.stocks];
	if (stock) {
		TicketStatus tStatus = [self lookupTicketStatus:stock];
		if (tStatus == TicketStatusNormal) {
			CheckInStatus cStatus = [self lookupCheckInStatus:stock];
			if (cStatus == CheckInStatusNo) {
				[CheckInActionHandler updateStocks:@[stock] toCheckIn:!stock.vendor_checkin commit:^(NSString *message) {
					[self showResult:stock];
				} rollback:^(NSString *message){
					[self beginReading];
				}];
			} else {
				[self showResult:stock];
			}
		} else {
			[self showResult:stock];
		}
	} else {
		[self quickScanTicket];
	}
}

- (SoldStock *)lookupStock:(NSArray *)stocks {
	return [stocks bk_match:^BOOL (SoldStock *obj) {
		return [obj.barcode isEqualToString:self.qrCode];
	}];
}

- (TicketStatus)lookupTicketStatus:(SoldStock *)stock {
	if (!stock) {
		return TicketStatusInvalid;
	} else {
		if (stock.product_id == self.product_id) {
			if ([stock.service_date compare:self.service_date] == NSOrderedAscending) {
				return TicketStatusExpired;
			} else if ([stock.service_date compare:self.service_date] == NSOrderedDescending) {
				return TicketStatusComing;
			}
			return TicketStatusNormal;
		} else {
			return TicketStatusOther;
		}
	}
}

- (CheckInStatus)lookupCheckInStatus:(SoldStock *)stock {
	if (!stock) {
		return CheckInStatusInvalid;
	} else {
		if (stock.vendor_checkin) {
			return CheckInStatusYes;
		} else {
			return CheckInStatusNo;
		}
	}
}

#pragma mark - Capture output delegate

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
	// NSLog(@"capture output %@ %@", [NSThread currentThread], [NSOperationQueue currentQueue]);
	AVMetadataMachineReadableCodeObject *codeObject = [metadataObjects bk_match:^BOOL (AVMetadataMachineReadableCodeObject *obj) {
		return [obj.type isEqualToString:[Vars appDelegate].loginUser.availableMetadataObjectType];
	}];
	if (!codeObject.stringValue || [self.qrCode isEqualToString:codeObject.stringValue]) {
		return;
	}
	self.qrCode = codeObject.stringValue;
	// NSLog(@"qrCode = %@", self.qrCode);
	AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
	[self performSelectorOnMainThread:@selector(stopReading) withObject:nil waitUntilDone:NO];
	dispatch_async(dispatch_get_main_queue(), ^{
		// NSLog(@"did handler %@ %@", [NSThread currentThread], [NSOperationQueue currentQueue]);
		[self postScan];
	});
}

@end
