import Foundation
import IdensicMobileSDK

@objc public class SumsubMobileSdk: NSObject {
    private var sdk: SNSMobileSDK?
    private weak var plugin: SumsubMobileSdkPlugin?
    public var isInitialized: Bool = false
    
    @objc public func initialize(accessToken: String, plugin: SumsubMobileSdkPlugin, email: String? = nil, phone: String? = nil, debug: Bool = false, locale: String? = nil, isAnalyticsEnabled: Bool = true) {
        self.plugin = plugin
        
        sdk = SNSMobileSDK(accessToken: accessToken)
        
        guard let unwrappedSdk = sdk, unwrappedSdk.isReady else {
            self.plugin?.logHandler(level: .error, message: ("Initialization failed: " + (sdk?.verboseStatus ?? "Unknown error")))
            return
        }
        isInitialized = true

        if email != nil {
            sdk?.initialEmail = email
        }
        if phone != nil {
            sdk?.initialPhone = phone
        }
        if debug {
            sdk?.logLevel = .debug
        }
        if let locale = locale {
            sdk?.locale = locale
        }
        sdk?.isAnalyticsEnabled = isAnalyticsEnabled
        
        // Handlers (https://docs.sumsub.com/docs/handlers)
        sdk?.tokenExpirationHandler { [weak self] (onComplete) in
            guard let self = self else {
                onComplete(nil)
                return
            }
            
            self.plugin?.requestNewToken({ (token: String?, error: Error?) -> Void in
                if let token = token {
                    onComplete(token)
                } else {
                    print("Error requesting new token: \(error?.localizedDescription ?? "Unknown error")")
                    onComplete(nil)
                }
            })
        }

        sdk?.verificationHandler { [weak self] (isApproved) in
            print("verificationHandler: Applicant is " + (isApproved ? "approved" : "finally rejected"))
            self?.plugin?.notifyApprovalStatus(isApproved)
        }

        // Status change (https://docs.sumsub.com/docs/callbacks#status-updates-notification)
        sdk?.onStatusDidChange { [weak self] (sdk, prevStatus) in
            print("onStatusDidChange: [\(sdk.description(for: prevStatus))] -> [\(sdk.description(for: sdk.status))]")

            // If fail, fire a special event
            if sdk.status == .failed {
                print("onStatusDidChange: [\(sdk.description(for: prevStatus))] -> [\(sdk.description(for: sdk.status))]")
                self?.plugin?.notifyFailStatus(sdk.description(for: sdk.failReason))
            }
            
            self?.plugin?.notifyStatusChanged(
                prevStatus: prevStatus,
                newStatus: sdk.status,
                statusDescription: sdk.description(for: sdk.status),
                verboseStatus: sdk.verboseStatus,
                failReason: sdk.description(for: sdk.failReason)
            )
        }

        // Events (https://docs.sumsub.com/docs/callbacks#events-notification)
        sdk?.onEvent { [weak self] (sdk, event) in
            print("onEvent: eventType=\(event.description(for: event.eventType)) payload=\(event.payload)")
            
            let stringPayload = event.payload.reduce(into: [String: Any]()) { result, keyValue in
                // Convert SNSEventKey to String
                let stringKey = "\(keyValue.key)"
                result[stringKey] = keyValue.value
            }
            self?.plugin?.notifyEvent(eventName: event.description(for: event.eventType), payload: stringPayload)

            switch event.eventType {
                case .applicantLoaded:
                    if let event = event as? SNSEventApplicantLoaded {
                        self?.plugin?.notifyApplicantLoaded(event.applicantId)
                    }

                case .stepInitiated:
                    if let event = event as? SNSEventStepInitiated {
                        self?.plugin?.notifyStepInitiated(event.idDocSetType)
                    }

                case .stepCompleted:
                    if let event = event as? SNSEventStepCompleted {
                        self?.plugin?.notifyStepCompleted(step: event.idDocSetType, isCancelled: event.isCancelled)
                    }

                case .analytics:
                    if let event = event as? SNSEventAnalytics {
                        self?.plugin?.notifyAnalyticsEvent(eventName: event.eventName, payload: event.eventPayload ?? [:])
                    }

                @unknown default:
                    print("Unknown Event: eventType=\(event.description(for: event.eventType)) payload=\(event.payload)")
                }
        }

        // https://docs.sumsub.com/docs/callbacks#dismiss-notification
        sdk?.onDidDismiss { [weak self] (sdk) in
            self?.plugin?.notifyDidDismiss(status: sdk.status, description: sdk.description(for: sdk.status))
        }

        // https://docs.sumsub.com/docs/logging#log-interception
        sdk?.logHandler { [weak self] (level, message) in
            self?.plugin?.logHandler(level: level, message: (message))
        }
    }
    
    @objc public func present(from viewController: UIViewController, completion: @escaping (Error?) -> Void, dismissalTimeInterval: TimeInterval = 3) {
        guard let sdk = sdk else {
            completion(NSError(domain: "SNSMobileSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "SDK not initialized"]))
            return
        }
        
//         sdk.setOnApproveDismissalTimeInterval(dismissalTimeInterval)
        sdk.present(from: viewController)
        completion(nil)
    }
    
    @objc public func dismiss() {
        guard let sdk = sdk else {
            print("SDK not initialized")
            return
        }
        sdk.dismiss()
    }

    @objc public func getVerificationStatus() -> SNSMobileSDK.Status {
        return sdk?.status ?? .failed
    }
}
