//
//  ScanCodeVC.swift
//  WoWonder
//
//  Created by iMac on 25/05/24.
//  Copyright © 2024 ScriptSun. All rights reserved.
//

import UIKit
import AVFoundation
import Async
import WowonderMessengerSDK
import Toast_Swift

class ScanCodeVC: BaseVC, AVCaptureMetadataOutputObjectsDelegate {
    
    // MARK: - Properties
    
    var parentContorller: QRCodeVC!
    var squareView: SquareView?
    //Default Properties
    let bottomSpace: CGFloat = 0.0
    var devicePosition: AVCaptureDevice.Position = .back
    open var qrScannerFrame: CGRect = CGRect.zero
    //Initialization part
    lazy var captureSession = AVCaptureSession()
    var user_data: UserData?
    
    // MARK: - View Life Cycles

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        
        self.initialConfig()
    }
    
    override public func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        //Currently only "Portraint" mode is supported
        UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
        prepareQRScannerView(self.view)
        startScanningQRCode()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        captureSession.stopRunning()
        removeVideoPriviewlayer()
    }
    
    // MARK: - Helper Functions
    
    // Initial Config
    func initialConfig() {
        
    }
    
    static func scanCodeVC() -> ScanCodeVC {
        let newVC = R.storyboard.dashboard.scanCodeVC()
        return newVC!
    }
    
    /// Lazy initialization of properties
    lazy var defaultDevice: AVCaptureDevice? = {
        if let device = AVCaptureDevice.default(for: .video) {
            return device
        }
        
        return nil
    }()
    
    lazy var frontDevice: AVCaptureDevice? = {
        if #available(iOS 10, *) {
            if let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front) {
                return device
            }
        } else {
            for device in AVCaptureDevice.devices(for: .video) {
                if device.position == .front {
                    return device
                }
            }
        }
        return nil
    }()
    
    lazy var defaultCaptureInput: AVCaptureInput? = {
        if let captureDevice = defaultDevice {
            do {
                return try AVCaptureDeviceInput(device: captureDevice)
            } catch let error as NSError {
                print(error)
            }
        }
        return nil
    }()
    
    lazy var frontCaptureInput: AVCaptureInput?  = {
        if let captureDevice = frontDevice {
            do {
                return try AVCaptureDeviceInput(device: captureDevice)
            } catch let error as NSError {
                print(error)
            }
        }
        return nil
    }()
    
    lazy var dataOutput = AVCaptureMetadataOutput()
    
    lazy var videoPreviewLayer: AVCaptureVideoPreviewLayer = {
        let layer = AVCaptureVideoPreviewLayer(session: self.captureSession)
        layer.videoGravity = AVLayerVideoGravity.resizeAspectFill
        return layer
    }()
    
    open func prepareQRScannerView(_ view: UIView) {
        qrScannerFrame = view.frame
        setupCaptureSession(devicePosition)//Default device capture position is back
        addViedoPreviewLayer(view)
        createCornerFrame()
    }
    
    private func createCornerFrame() {
        let width: CGFloat = self.view.width - 100
        let rect = CGRect.init(origin: CGPoint.init(x: self.view.frame.width/2 - width/2, y: self.view.frame.height/2 - (width+bottomSpace)/2), size: CGSize.init(width: width, height: width))
        self.squareView = SquareView(frame: rect)
        squareView?.sizeMultiplier = 0.3
        squareView?.lineWidth = 20
        squareView?.lineColor = .color_fill
        if let squareView = squareView {
            self.view.addSubview(squareView)
        }
    }
    
    private func getCurrentInput() -> AVCaptureDeviceInput? {
        if let currentInput = captureSession.inputs.first as? AVCaptureDeviceInput {
            return currentInput
        }
        return nil
    }
    
    open func startScanningQRCode() {
        if captureSession.isRunning {
            return
        }
        captureSession.startRunning()
    }
    
    private func setupCaptureSession(_ devicePostion: AVCaptureDevice.Position) {
        
        if captureSession.isRunning {
            return
        }
        
        switch devicePosition {
        case .front:
            if let frontDeviceInput = frontCaptureInput {
                if !captureSession.canAddInput(frontDeviceInput) {
                    self.parentContorller.view.makeToast("Failed to add Input")
                    return
                }
                captureSession.addInput(frontDeviceInput)
            }
            break;
        case .back, .unspecified :
            if let defaultDeviceInput = defaultCaptureInput {
                if !captureSession.canAddInput(defaultDeviceInput) {
                    self.parentContorller.view.makeToast("Failed to add Input")
                    return
                }
                captureSession.addInput(defaultDeviceInput)
            }
            break
            
        }
        
        if !captureSession.canAddOutput(dataOutput) {
            self.parentContorller.view.makeToast("Failed to add Input")
            return
        }
        
        captureSession.addOutput(dataOutput)
        dataOutput.metadataObjectTypes = dataOutput.availableMetadataObjectTypes
        dataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
    }
    
    private func addViedoPreviewLayer(_ view: UIView) {
        videoPreviewLayer.frame = CGRect(x:view.bounds.origin.x, y: view.bounds.origin.y, width: view.bounds.size.width, height: view.bounds.size.height - bottomSpace)
        view.layer.insertSublayer(videoPreviewLayer, at: 0)
    }
    
    private func removeVideoPriviewlayer() {
        videoPreviewLayer.removeFromSuperlayer()
    }
    
    /// This method get called when Scanning gets complete
    public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        for data in metadataObjects {
            let transformed = videoPreviewLayer.transformedMetadataObject(for: data) as? AVMetadataMachineReadableCodeObject
            if let unwraped = transformed {
                if let stringValue = unwraped.stringValue {
                    if stringValue.contains(API.baseURL) {
                        if let url = URL(string: stringValue) {
                            let pathComponents = url.pathComponents
                            if pathComponents.count > 1 {
                                let username = pathComponents[1]
                                self.getUserDataByUsername(username: username)
                            }
                        } else {
                            self.parentContorller.view.makeToast("There is no user for this code")
                        }
                    } else {
                        self.parentContorller.view.makeToast("There is no user for this code")
                    }
                } else {
                    self.parentContorller.view.makeToast("Empty string found")
                }
            }
        }
    }
    
}

//Currently Scanner suppoerts only portrait mode.

extension ScanCodeVC {
    ///Make orientations to portrait
    override public var shouldAutorotate: Bool {
        return false
    }
    
    override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.portrait
    }
    
    override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return UIInterfaceOrientation.portrait
    }
}

// MARK: Api Call
extension ScanCodeVC {
    
    func getUserDataByUsername(username: String) {
        if Connectivity.isConnectedToNetwork() {
            captureSession.stopRunning()
            self.showProgressDialog(text: NSLocalizedString("Loading...", comment: "Loading..."))
            Async.background {
                GetUserDataManager.instance.getUserDataByUsername(username: username, session_Token: AppInstance.instance._sessionId, send_notify: 1) { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                guard let user = success?.user_data else { return }
                                self.user_data = user
                                if let messageAlertVC = R.storyboard.popup.messageAlertVC() {
                                    messageAlertVC.delegate = self
                                    messageAlertVC.messageText = "Do you want to open this profile @\(user.username ?? "")"
                                    messageAlertVC.confirmText = "OPEN"
                                    self.parentContorller.present(messageAlertVC, animated: true, completion: nil)
                                }
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.startScanningQRCode()
                                self.view.makeToast(sessionError?.errors?.error_text ?? "")
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.startScanningQRCode()
                                self.view.makeToast(serverError?.errors?.error_text)
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.startScanningQRCode()
                                self.view.makeToast(error?.localizedDescription)
                            }
                        }
                    }
                }
            }
        } else {
            self.dismissProgressDialog {
                self.view.makeToast(NSLocalizedString("Internet Error", comment: "Internet Error"))
            }
        }
    }
    
}

// MARK: - MessageAlertVCDelegate
extension ScanCodeVC: MessageAlertVCDelegate {
    
    func messageAlertConfirmButtonPressed(_ sender: UIButton) {
        if let newVC = R.storyboard.dashboard.userProfileViewController() {
            newVC.user_id =  self.user_data?.user_id ?? ""
            newVC.user_data = self.user_data
            newVC.admin = self.user_data?.admin ?? ""
            newVC.isFromQRCode = true
            self.parentContorller.navigationController?.pushViewController(newVC, animated: true)
        }
    }
    
    func messageAlertCloseButtonPressed(_ sender: UIButton) {
        self.startScanningQRCode()
    }
    
}

/** This class is for draw corners of Square to show frame for scan QR code.
 *  @IBInspectable parameters are the line color, sizeMultiplier, line width.
 */
@IBDesignable
class SquareView: UIView {
    @IBInspectable
    var sizeMultiplier : CGFloat = 0.2 {
        didSet{
            self.draw(self.bounds)
        }
    }
    
    @IBInspectable
    var lineWidth : CGFloat = 2 {
        didSet{
            self.draw(self.bounds)
        }
    }
    
    @IBInspectable
    var lineColor : UIColor = UIColor.green {
        didSet{
            self.draw(self.bounds)
        }
    }
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.clear
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.backgroundColor = UIColor.clear
    }
    
    func drawCorners() {
        let currentContext = UIGraphicsGetCurrentContext()
        
        currentContext?.setLineWidth(lineWidth)
        currentContext?.setStrokeColor(lineColor.cgColor)
        currentContext?.setLineCap(.round)

        //top left corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: 0, y: 0))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width*sizeMultiplier, y: 0))
        currentContext?.strokePath()
        
        //top rigth corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: self.bounds.size.width - self.bounds.size.width*sizeMultiplier, y: 0))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width, y: 0))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width, y: self.bounds.size.height*sizeMultiplier))
        currentContext?.strokePath()
        
        //bottom rigth corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: self.bounds.size.width, y: self.bounds.size.height - self.bounds.size.height*sizeMultiplier))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width, y: self.bounds.size.height))
        currentContext?.addLine(to: CGPoint(x: self.bounds.size.width - self.bounds.size.width*sizeMultiplier, y: self.bounds.size.height))
        currentContext?.strokePath()
        
        //bottom left corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: self.bounds.size.width*sizeMultiplier, y: self.bounds.size.height))
        currentContext?.addLine(to: CGPoint(x: 0, y: self.bounds.size.height))
        currentContext?.addLine(to: CGPoint(x: 0, y: self.bounds.size.height - self.bounds.size.height*sizeMultiplier))
        currentContext?.strokePath()
        
        //second part of top left corner
        currentContext?.beginPath()
        currentContext?.move(to: CGPoint(x: 0, y: self.bounds.size.height*sizeMultiplier))
        currentContext?.addLine(to: CGPoint(x: 0, y: 0))
        currentContext?.strokePath()
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        self.drawCorners()
    }
    
}
