package com.nimiq.plugins.sumsubsdk import android.os.Build import com.getcapacitor.* import com.getcapacitor.annotation.CapacitorPlugin import com.sumsub.sns.core.data.model.SNSSDKState import java.text.SimpleDateFormat import java.time.Instant import java.time.format.DateTimeFormatter import java.util.Date import java.util.TimeZone @CapacitorPlugin(name = "SumsubMobileSdk") class SumsubMobileSdkPlugin : Plugin() { private val implementation = SumsubMobileSdk() @PluginMethod fun initialize(call: PluginCall) { try { val accessToken = call.getString("accessToken") if (accessToken == null) { call.reject("Access token is required") return } val applicantConfig = call.getObject("applicantConfig", JSObject()) val email = applicantConfig?.getString("email") val phone = applicantConfig?.getString("phone") val debug = call.getBoolean("debug", false) val locale = call.getString("locale") val isAnalyticsEnabled = call.getBoolean("isAnalyticsEnabled", true) val dismissalTimeInterval = call.getInt("dismissalTimeInterval") ?: 3 activity?.runOnUiThread { try { implementation.initialize( accessToken = accessToken, plugin = this, email = email, phone = phone, debug = debug, locale = locale, isAnalyticsEnabled = isAnalyticsEnabled, dismissalTimeInterval = dismissalTimeInterval ) call.resolve(JSObject().apply { put("status", mapStatus(implementation.getVerificationStatus()) ) }) } catch (e: Exception) { call.reject("Failed to initialize SDK: ${e.message}", e) } } ?: call.reject("Activity not available") } catch (e: Exception) { call.reject("Failed to initialize SDK: ${e.message}", e) } } @PluginMethod fun present(call: PluginCall) { if (!implementation.isInitialized) { call.reject("SDK not initialized") return } activity?.runOnUiThread { try { implementation.present(activity!!) call.resolve() } catch (e: Exception) { call.reject("Failed to present SDK: ${e.message}", e) } } ?: call.reject("Activity not available") } @PluginMethod fun dismiss(call: PluginCall) { if (!implementation.isInitialized) { call.reject("SDK not initialized") return } try { implementation.dismiss() call.resolve() } catch (e: Exception) { call.reject("Failed to dismiss SDK: ${e.message}", e) } } @PluginMethod fun setAccessToken(call: PluginCall) { val token = call.getString("token") if (token == null) { call.reject("No token provided") return } implementation.setToken(token) call.resolve() } @PluginMethod fun getVerificationStatus(call: PluginCall) { if (!implementation.isInitialized) { call.reject("SDK not initialized") return } call.resolve(JSObject().apply { put("status", mapStatus(implementation.getVerificationStatus())) }) } // Methods to handle events and callbacks from the SDK fun requestNewToken() { notifyListeners("onTokenExpired", JSObject()) } fun notifyStatusChanged( prevStatus: SNSSDKState, newStatus: SNSSDKState, statusDescription: String, verboseStatus: String, failReason: String ) { val data = JSObject().apply { put("prevStatus", mapStatus(prevStatus)) put("newStatus", mapStatus(newStatus)) put("statusDescription", statusDescription) put("verboseStatus", verboseStatus) put("failReason", failReason) } notifyListeners("onVerificationStatusChanged", data) } fun notifyFailStatus(failReason: String?) { val data = JSObject().apply { put("failReason", failReason ?: "Unknown error") } notifyListeners("onVerificationFailed", data) } fun notifyApprovalStatus(isApproved: Boolean) { val data = JSObject().apply { put("isApproved", isApproved) } notifyListeners("onApprovedStatusChanged", data) } fun notifyApplicantLoaded(applicantId: String) { val data = JSObject().apply { put("applicantId", applicantId) } notifyListeners("onApplicantLoaded", data) } fun notifyStepInitiated(step: String) { val data = JSObject().apply { put("step", step) } notifyListeners("onStepInitiated", data) } fun notifyStepCompleted(step: String, isCancelled: Boolean) { val data = JSObject().apply { put("step", step) put("isCancelled", isCancelled) } notifyListeners("onStepCompleted", data) } fun notifyAnalyticsEvent(eventName: String, payload: Map) { val data = JSObject().apply { put("eventName", eventName) val payloadObject = JSObject() for ((key, value) in payload) { payloadObject.put(key, value) } put("payload", payloadObject) } notifyListeners("onAnalyticsEvent", data) } fun notifyEvent(eventName: String, payload: Map?) { val data = JSObject().apply { put("eventName", eventName) val payloadObject = JSObject() for ((key, value) in payload ?: emptyMap()) { payloadObject.put(key, value) } put("payload", payloadObject) } notifyListeners("onEvent", data) } fun notifyDidDismiss(status: SNSSDKState?, description: String) { val data = JSObject().apply { put("status", mapStatus(status)) put("description", description) } notifyListeners("onDidDismiss", data) } fun logHandler(level: String, message: String) { val timestamp = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { DateTimeFormatter.ISO_INSTANT.format(Instant.now()) } else { val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") formatter.timeZone = TimeZone.getTimeZone("UTC") formatter.format(Date()) } val data = JSObject().apply { put("level", level) put("message", "$timestamp [$level] $message") } notifyListeners("onLog", data) } private fun mapStatus(status: SNSSDKState?): String { return when (status) { SNSSDKState.Ready -> "Ready" SNSSDKState.Initial -> "Initial" SNSSDKState.Approved -> "Approved" SNSSDKState.FinallyRejected -> "FinallyRejected" SNSSDKState.Pending -> "Pending" SNSSDKState.Incomplete -> "Incomplete" SNSSDKState.TemporarilyDeclined -> "TemporarilyDeclined" else -> "Unknown" } } }