import Foundation
import React
import DocumentDetector

private struct DocumentDetectorEvents {
    static let documentDetectorSuccessEvent: String = "DocumentDetector_Success"
    static let documentDetectorErrorEvent: String = "DocumentDetector_Error"
    static let documentDetectorCancelEvent: String = "DocumentDetector_Cancel"
}

@objc(CafDocumentDetector)
class CafDocumentDetector: RCTEventEmitter, DocumentDetectorControllerDelegate {
    static let shared = CafDocumentDetector()
    
    @objc
    override static func requiresMainQueueSetup() -> Bool {
        return true
    }
    
    @objc(startDocumentDetector:personId:config:)
    func startDocumentDetector(mobileToken: String, personId: String, config: String) {
        guard let configDictionary = parseConfig(config) else {
            handleError(
                statusCode: ErrorStatusCode.statusCode500,
                message: ErrorMessage.unableStartSDK,
                type: ErrorReason.libraryReason
            )
            return
        }
        
        let cafDocumentDetector = DocumentDetectorBuilder()
        
        do {
            let documentDetectorBuilder = try cafDocumentDetector.buildDocumentDetectorBuilder(
                mobileToken: mobileToken, personId: personId, configDictionary: configDictionary
            )
            
            DispatchQueue.main.async {
                guard let rootViewController = UIApplication.shared.currentKeyWindow?.rootViewController else {
                    self.handleError(
                        statusCode: ErrorStatusCode.statusCode500,
                        message: ErrorMessage.unableStartSDK,
                        type: ErrorReason.libraryReason
                    )
                    return
                }
                
                var currentViewController = rootViewController;
                
                while let presentedViewController = currentViewController.presentedViewController {
                    currentViewController = presentedViewController
                }
                
                let scannerVC = self.createScannerViewController(documentDetectorBuilder)
                currentViewController.present(scannerVC, animated: true)
            }
        } catch SDKError.invalidFormatMessage(let invalidFormatMessage) {
            handleError(
                statusCode: ErrorStatusCode.statusCode500,
                message: invalidFormatMessage,
                type: ErrorReason.libraryReason
            )
        } catch SDKError.requiredMethodMessage(let requiredMethodMessage) {
            handleError(
                statusCode: ErrorStatusCode.statusCode500,
                message: requiredMethodMessage,
                type: ErrorReason.libraryReason
            )
        } catch {
            handleError(
                statusCode: ErrorStatusCode.statusCode500,
                message: error.localizedDescription,
                type: ErrorReason.libraryReason
            )
        }
    }
    
    private func parseConfig(_ config: String) -> [String: Any]? {
        guard let data = config.data(using: .utf8),
              let configDictionary = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
        else {
            return nil
        }
        return configDictionary
    }
    
    private func createScannerViewController(_ documentDetectorBuilder: DocumentDetectorSdk.CafBuilder) -> DocumentDetectorController {
        let scannerVC = DocumentDetectorController(documentDetector: documentDetectorBuilder.build())
        scannerVC.documentDetectorDelegate = self
        return scannerVC
    }
    
    private func handleError(statusCode: String, message: String, type: String) {
        var map = [String: String]()
        map[JSONProperties.statusCode] = statusCode
        map[JSONProperties.message] = message
        map[JSONProperties.type] = type
        sendEvent(withName: DocumentDetectorEvents.documentDetectorErrorEvent, body: map)
    }
    
    // DocumentDetector Events
    func documentDetectionController(_ scanner: DocumentDetector.DocumentDetectorController, didFinishWithResults results: DocumentDetector.DocumentDetectorResult) {
        sendEvent(withName: DocumentDetectorEvents.documentDetectorSuccessEvent, body: EncodeJSON.createCaptureMap(result: results)
        )
    }
    
    func documentDetectionControllerDidCancel(_ scanner: DocumentDetector.DocumentDetectorController) {
        sendEvent(withName: DocumentDetectorEvents.documentDetectorCancelEvent, body: true)
    }
    
    func documentDetectionController(_ scanner: DocumentDetector.DocumentDetectorController, didFailWithError error: DocumentDetector.CafDocumentDetectorFailure) {
        sendEvent(withName: DocumentDetectorEvents.documentDetectorErrorEvent, body: EncodeJSON.createErrorMap(sdkFailure: error)
        )
    }
    
    override func supportedEvents() -> [String]! {
        return [
            DocumentDetectorEvents.documentDetectorSuccessEvent,
            DocumentDetectorEvents.documentDetectorCancelEvent,
            DocumentDetectorEvents.documentDetectorErrorEvent
        ]
    }
}
