//
//  QRCodeScanner.swift
//  QRView
//
//  Created by LISA on 2017/7/19.
//  Copyright © 2017年 FFIB. All rights reserved.
//

import UIKit
import AVFoundation
class QRCodeScanner: NSObject {
    var didDecodeCode: ((QRCodeScanResult) -> Void)?
    var didDecodeFail: ((NSError) -> Void)?
    fileprivate let captureSession = AVCaptureSession()
    fileprivate let input: AVCaptureInput? = {
        guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { return nil }
        return try? AVCaptureDeviceInput(device: device)
    }()
    fileprivate let output = AVCaptureMetadataOutput()
    var previewLayer: AVCaptureVideoPreviewLayer?
    fileprivate var avaliable = true
    var scanRect: CGRect

    init(scanRect: CGRect) {
        self.scanRect = scanRect
        super.init()
        commonInit()
    }

    fileprivate func commonInit() {
        #if !TARGET_INTERFACE_BUILDER && !((arch(i386) || arch(x86_64)))
            switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) {
            case .notDetermined:
                initCaputue()
                startCaputue()
                break
            case .authorized:
                self.initCaputue()
                self.startCaputue()
                break
            default:
                let alert = UIAlertView(title: "拒绝访问", message: "请在设置-隐私-相机中允许访问相机", delegate: nil, cancelButtonTitle: "确定")
                alert.show()
                self.avaliable = false
                break
            }
        #endif
    }
    fileprivate func initCaputue() {
        guard let input = self.input else { return }
        self.captureSession.sessionPreset = AVCaptureSession.Preset.hd1920x1080
        if self.captureSession.canAddInput(input) {
            self.captureSession.addInput(input)
        } else {
            self.avaliable = false
        }
        if self.captureSession.canAddOutput(self.output) {
            self.captureSession.addOutput(self.output)
            self.output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
            self.output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        } else {
            self.avaliable = false
        }
    }

    fileprivate func setScanArea() {
        //设置扫描区域
        let cropRect = CGRect(x: (self.scanRect.width - self.scanRect.width / 1.5) / 2,
                              y: (self.scanRect.height - self.scanRect.width / 1.5) / 2,
                              width: self.scanRect.width / 1.5,
                              height: self.scanRect.width / 1.5)
        output.rectOfInterest = CGRect(x: cropRect.origin.y / scanRect.height,
                                       y: cropRect.origin.x / scanRect.width,
                                       width: cropRect.height / scanRect.height,
                                       height: cropRect.width / scanRect.width)
    }

    fileprivate func startCaputue() {
        guard avaliable && !captureSession.isRunning else {
            print("QRCode camera not avaliable")
            return
        }
        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    }
    func startScan() {
        setScanArea()
        captureSession.startRunning()
    }

    func stopScan() {
        if captureSession.isRunning {
            captureSession.stopRunning()
        }
    }
    deinit {
        NotificationCenter.default.removeObserver(self, name: Notification.QRNotification.RestartNotification, object: nil)
    }

    func cueSound() {
        var soundId = SystemSoundID()
        AudioServicesCreateSystemSoundID(URL.init(fileURLWithPath: Bundle.main.path(forResource: "di", ofType: "mp3")!) as CFURL, &soundId)
        AudioServicesPlaySystemSound(soundId)
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
    }
}

extension QRCodeScanner: AVCaptureMetadataOutputObjectsDelegate {
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        guard let metadatas = metadataObjects as? [AVMetadataMachineReadableCodeObject],
            let res = metadatas.first?.stringValue, let type = metadataObjects.first?.type.rawValue else {
            let error = NSError.init(domain: "scan qr code failure",
                                     code: 102,
                                     userInfo: nil)
            didDecodeFail!(error)
            return
        }
        stopScan()
        cueSound()
        didDecodeCode!(QRCodeScanResult(metadataType: type, result: res))
    }
}