import Foundation
import FaceTecSDK

// This class demonstrates the most important integration point in the FaceTec Device SDK  -- The Session Request Processor.
//
// The Session Request Processor:
// - Implements an onSessionRequest function.  This function is called by the FaceTec Device SDK.
// - The onSessionRequest function is always passed a sessionRequestBlob, and you always send this blob up to your webservice, and into FaceTec Server.
// - The Session Request Blob is an encrypted string that you get and send to FaceTec Server.
// - Upon receiving the Response Blob from FaceTec Server, you will always call the sessionRequestCallback.processResponse function.
// - The Session Response Blob is an encrypted string that you get from FaceTec Server and pass back into the Device SDK.
// - The Session Request Callback  This is called when you receive a response from the FaceTec Server, with the blob that you receive from FaceTec Server.
// - The Session Request Callback provides a updateProgress function, where you can pass in the upload progress, controlling the Upload Screen Progress Bar.
//
// Notes:
// - Adding additional logic to this code is not allowed.  Do not add any additional logic outside of what is demonstrated in this Sample.
// - Adding additional asynchronous calls to this code is not allowed.  Only make your own additional asynchronous calls once the FaceTec UI is closed.
// - Adding code that modifies any App UI (Yours or FaceTec's) is not allowed.  Only add code that modifies your own App UI once the FaceTec UI is closed.
class SessionRequestProcessor: NSObject, FaceTecSessionRequestProcessor, URLSessionTaskDelegate {

    // Singleton instance
    static let shared = SessionRequestProcessor()

    // Completion callback for React Native bridge
    private var completionCallback: ((Bool, [String: Any]?) -> Void)?

    // Store server response data (similar to Android's setResult)
    private var serverResponseData: [String: Any]?

    private override init() {
        super.init()
    }

    // Set completion callback from React Native bridge
    func setCompletionCallback(_ callback: @escaping (Bool, [String: Any]?) -> Void) {
        self.completionCallback = callback
    }

    // Store server response (called from NetworkingRequest)
    func setServerResponse(_ response: [String: Any]) {
        self.serverResponseData = response
    }
    // onSessionRequest is the core method called by the FaceTec SDK when a request needs to be processed by the FaceTec SDK.
    // Your code must retrieve the Session Request Blob and send to your FaceTec Server.
    // Your code must retrieve the Response Blob from FaceTec Server and call processResponse, passing in the Response Blob.
    func onSessionRequest(sessionRequestBlob: String, sessionRequestCallback: FaceTecSessionRequestProcessorCallback) {
        // When you receive a Session Request Blob, call your webservice API that handles this object and passes it to FaceTec Server.
        // SampleAppNetworkingRequest is a demonstration class for making a networking call that passes the Session Request Blob, and handles the response.
        let request = NetworkingRequest(referencingProcessor: self, sessionRequestCallback: sessionRequestCallback)
        request.send(sessionRequestBlob: sessionRequestBlob)
    }

    // When the Response Blob is received, call processResponse with it.
    // Please note that onResponseBlobReceived is a convenience function set up on this class,
    // so that this function can be called asynchronously once you receive the Response Blob.
    func onResponseBlobReceived(responseBlob: String, sessionRequestCallback: FaceTecSessionRequestProcessorCallback) {
        sessionRequestCallback.processResponse(responseBlob);
    }

    // When upload progress is received from your webservice, call updateProgress to update the Progress Bar state.
    // Please note that onUploadProgress is a convenience function set up on this class,
    // so that this function can be called asynchronously when your networking code receives an upload progress event.
    func onUploadProgress(progress: Float, sessionRequestCallback: FaceTecSessionRequestProcessorCallback) {
        sessionRequestCallback.updateProgress(progress);
    }

    // Calling abortOnCatastrophicError is not allowed except for catastrophic network failures.
    // Calling abortOnCatastrophicError to exit the FaceTec UI with custom logic is not allowed.
    func onCatastrophicNetworkError(sessionRequestCallback: FaceTecSessionRequestProcessorCallback) {
        sessionRequestCallback.abortOnCatastrophicError();
    }

    // The onFaceTecExit API is the method called when the FaceTec SDK completes or cancels.
    func onFaceTecExit(sessionResult: FaceTecSessionResult) {
        DispatchQueue.main.async {
            let sessionStatus = sessionResult.sessionStatus

            // Handle successful completion
            if sessionStatus == .sessionCompleted {
                // Return the complete server response data (like Android does)
                if let serverData = self.serverResponseData {
                    self.completionCallback?(true, serverData)
                } else {
                    // Fallback if no server data was stored
                    self.completionCallback?(true, ["success": true, "sessionStatus": "completed"])
                }
                // Clear server response data for next session
                self.serverResponseData = nil
            } else {
                // Handle non-successful sessions
                let errorMessage = self.getErrorMessage(for: sessionStatus)
                self.completionCallback?(false, ["error": errorMessage, "sessionStatus": sessionStatus.rawValue])
            }
        }
    }

    private func getErrorMessage(for status: FaceTecSessionStatus) -> String {
        switch status {
        case .sessionCompleted:
            return "Session was completed."
        case .requestAborted:
            return "Session was cancelled because abortOnCatastrophicError() was called."
        case .cameraPermissionsDenied:
            return "FaceTec SDK was unable to access the Camera due to the User's Settings or an Administrator Policy"
        case .userCancelledFaceScan:
            return "The user cancelled before performing enough Scans to Succeed."
        case .userCancelledIDScan:
            return "The User cancelled before completing all of the steps in the ID Scan Process."
        case .lockedOut:
            return "FaceTec SDK is in a lockout state."
        case .cameraError:
            return "Session cancelled due to a camera error."
        case .unknownInternalError:
            return "Session failed because an unknown or unexpected error occurred."
        }
    }
}
