package com.margelo.nitro.fawrypay.rnfawrypaysdk import android.app.Activity import android.os.Handler import android.os.Looper import android.util.Log import com.facebook.proguard.annotations.DoNotStrip import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.ReadableType import com.fawry.fawrypay.domain.models.* import com.fawry.fawrypay.utils.CardManagerCallbacks import com.fawry.fawrypay.utils.FawrySdkCallbacks import com.fawry.fawrypay.utils.fawrySdk.LaunchFawrySdk import com.fawry.fawrypay.utils.fawrySdk.enums.Languages import com.fawry.fawrypay.utils.fawrySdk.enums.PaymentStatus import com.google.gson.Gson import com.margelo.nitro.NitroModules import org.json.JSONObject import java.util.concurrent.atomic.AtomicBoolean @DoNotStrip class RnFawryPaySdk : HybridRnFawryPaySdkSpec() { private val mainHandler = Handler(Looper.getMainLooper()) private val active = AtomicBoolean(true) @Volatile private var listener: ((String, String) -> Unit)? = null private val listenerLock = Any() companion object { const val NAME = "RnFawryPaySdk" const val SDK_VERSION = "2.0.5" const val EVENT_PAYMENT_COMPLETED = "EVENT_PAYMENT_COMPLETED" const val EVENT_ON_SUCCESS = "EVENT_ON_SUCCESS" const val EVENT_ON_FAIL = "EVENT_ON_FAIL" const val EVENT_CardManager_FAIL = "EVENT_CardManager_FAIL" const val EVENT_COMPLETION_BLOCK = "EVENT_COMPLETION_BLOCK" const val EVENT_PRE_COMPLETION = "EVENT_PRE_COMPLETION" const val EVENT_READY = "EVENT_READY" } override fun addListener(listener: (String, String) -> Unit): () -> Unit { synchronized(listenerLock) { active.set(true) this.listener = listener } emit(EVENT_READY, "SDK Ready") return { synchronized(listenerLock) { active.set(false) this.listener = null } } } private fun emit(event: String, payload: Any?) { if (!active.get()) return mainHandler.post { if (!active.get()) return@post val callback = synchronized(listenerLock) { listener } if (callback == null) return@post try { val jsonPayload = when (payload) { is String -> payload is ReadableMap -> convertReadableMapToJson(payload) else -> convertToJson(payload) } callback(event, jsonPayload) } catch (t: Throwable) { Log.e(NAME, "Emit failed for $event", t) } } } private fun convertToJson(obj: Any?): String { return try { when (obj) { is Map<*, *> -> JSONObject(obj as Map).toString() else -> Gson().toJson(obj) } } catch (e: Exception) { "{\"error\":\"Failed to serialize payload\"}" } } private fun convertReadableMapToJson(map: ReadableMap): String { return try { val json = JSONObject() val iterator = map.keySetIterator() while (iterator.hasNextKey()) { val key = iterator.nextKey() when (map.getType(key)) { ReadableType.Null -> json.put(key, JSONObject.NULL) ReadableType.Boolean -> json.put(key, map.getBoolean(key)) ReadableType.Number -> json.put(key, map.getDouble(key)) ReadableType.String -> json.put(key, map.getString(key)) ReadableType.Map -> json.put(key, map.getMap(key)?.toString()?.let { JSONObject(it) }) ReadableType.Array -> json.put(key, map.getArray(key)?.toString()?.let { JSONObject(it) }) } } json.toString() } catch (e: Exception) { Log.e(NAME, "Error converting ReadableMap", e) "{\"error\":\"Failed to serialize ReadableMap\"}" } } override fun multiply(a: Double, b: Double): Double = a * b override fun startPayment(model: FawryLaunchModel) { val activity = NitroModules.applicationContext?.currentActivity if (activity == null) { Log.e(NAME, "startPayment failed: no current Activity") return } val modelString = convertToJson(model) Log.d("RnFawryPaySdk", "startPayment called with react model: $modelString") val selectedLang = when (model.lang) { FawryLanguages.ARABIC -> Languages.ARABIC FawryLanguages.ENGLISH -> Languages.ENGLISH } val launchModel = FawryModelConverter.convert(model) LaunchFawrySdk.launchAnonymousSDK( activity, selectedLang, model.baseUrl, launchModel, object : FawrySdkCallbacks { override fun onSuccess( paymentStatus: PaymentStatus, data: CreatePayRefNoResponse? ) { emit(EVENT_ON_SUCCESS, data) } override fun onPaymentCompleted( paymentStatus: PaymentStatus, data: CreatePayRefNoResponse?, error: FawryPayError? ) { emit(EVENT_PAYMENT_COMPLETED, data) } override fun onFailure(error: FawryPayError) { emit(EVENT_ON_FAIL, error) } } ) } override fun openCardsManager( baseUrl: String, lang: FawryLanguages, merchantInfo: MerchantInfo, customerInfo: CustomerInfo, tokenizationSignature: String? ) { val activity = NitroModules.applicationContext?.currentActivity if (activity == null) { Log.e(NAME, "openCardsManager failed: no current Activity") return } val selectedLang = when (lang) { FawryLanguages.ARABIC -> Languages.ARABIC FawryLanguages.ENGLISH -> Languages.ENGLISH } val launchModel = com.fawry.fawrypay.domain.models.FawryLaunchModel( launchCustomerModel = Gson().fromJson( convertToJson(customerInfo), LaunchCustomerModel::class.java ), launchMerchantModel = Gson().fromJson( convertToJson(merchantInfo), LaunchMerchantModel::class.java ).apply { this.secretCode = merchantInfo.merchantSecretCode }, tokenizationSignature = tokenizationSignature ) LaunchFawrySdk.launchCardManagerFlow( activity, selectedLang, baseUrl, launchModel, object : CardManagerCallbacks { override fun onSuccess(message: String) { emit(EVENT_ON_SUCCESS, message) } override fun onFailure(error: String) { emit(EVENT_CardManager_FAIL, error) } } ) } }