package expo.modules.mercadopago import android.app.Activity import android.content.Intent import com.mercadopago.android.px.core.MercadoPagoCheckout import com.mercadopago.android.px.model.Payment import com.mercadopago.android.px.model.PaymentData import com.mercadopago.android.px.model.PaymentResult import com.mercadopago.android.px.model.exceptions.MercadoPagoError import expo.modules.core.ExportedModule import expo.modules.core.ModuleRegistry import expo.modules.core.Promise import expo.modules.core.interfaces.ActivityEventListener import expo.modules.core.interfaces.ActivityProvider import expo.modules.core.interfaces.services.EventEmitter import org.json.JSONObject class ExpoMercadoPagoModule : ExportedModule, ActivityEventListener { private val NAME = "ExpoMercadoPagoModule" private var moduleRegistry: ModuleRegistry? = null private var currentPromise: Promise? = null private var publicKey: String? = null private var siteId: String = "MLA" private var language: String = "es" override fun getName(): String = NAME override fun onCreate(moduleRegistry: ModuleRegistry) { this.moduleRegistry = moduleRegistry moduleRegistry.getModule(ActivityProvider::class.java)?.addActivityEventListener(this) } override fun onDestroy() { moduleRegistry?.getModule(ActivityProvider::class.java)?.removeActivityEventListener(this) } @ExportedModule.ExportedMethod fun initializeAsync(config: Map, promise: Promise) { try { publicKey = config["publicKey"] as? String siteId = config["siteId"] as? String ?: "MLA" language = config["language"] as? String ?: "es" if (publicKey.isNullOrEmpty()) { promise.reject("INVALID_CONFIG", "Public key is required") return } promise.resolve(null) } catch (e: Exception) { promise.reject("INIT_ERROR", "Failed to initialize: ${e.message}") } } @ExportedModule.ExportedMethod fun startPaymentAsync(preferenceId: String, promise: Promise) { if (publicKey.isNullOrEmpty()) { promise.reject("NOT_INITIALIZED", "Module not initialized. Call initializeAsync first.") return } val activity = moduleRegistry?.getModule(ActivityProvider::class.java)?.currentActivity if (activity == null) { promise.reject("NO_ACTIVITY", "No activity available") return } currentPromise = promise try { val builder = MercadoPagoCheckout.Builder(publicKey!!, preferenceId) val checkout = builder.build() checkout.startPayment(activity, REQUEST_CODE) } catch (e: Exception) { promise.reject("PAYMENT_ERROR", "Failed to start payment: ${e.message}") } } @ExportedModule.ExportedMethod fun isMercadoPagoInstalledAsync(promise: Promise) { try { val activity = moduleRegistry?.getModule(ActivityProvider::class.java)?.currentActivity val packageManager = activity?.packageManager val isInstalled = try { packageManager?.getPackageInfo("com.mercadopago.android", 0) true } catch (e: Exception) { false } promise.resolve(isInstalled) } catch (e: Exception) { promise.reject("CHECK_ERROR", "Failed to check if MercadoPago is installed: ${e.message}") } } @ExportedModule.ExportedMethod fun getSDKVersionAsync(promise: Promise) { try { val version = MercadoPagoCheckout.VERSION promise.resolve(version) } catch (e: Exception) { promise.reject("VERSION_ERROR", "Failed to get SDK version: ${e.message}") } } override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == REQUEST_CODE) { val promise = currentPromise currentPromise = null if (promise == null) { return } when (resultCode) { MercadoPagoCheckout.PAYMENT_RESULT_CODE -> { val payment = data?.getParcelableExtra(MercadoPagoCheckout.EXTRA_PAYMENT_RESULT) if (payment != null) { val result = createPaymentResult(payment) promise.resolve(result) emitPaymentResult(result) } else { promise.reject("PAYMENT_ERROR", "No payment result received") } } MercadoPagoCheckout.ERROR_RESULT_CODE -> { val error = data?.getParcelableExtra(MercadoPagoCheckout.EXTRA_ERROR) if (error != null) { val errorResult = createErrorResult(error) promise.reject("PAYMENT_ERROR", error.message, errorResult) emitPaymentResult(errorResult) } else { promise.reject("PAYMENT_ERROR", "Unknown payment error") } } Activity.RESULT_CANCELED -> { val cancelResult = createCancelResult() promise.reject("PAYMENT_CANCELLED", "Payment was cancelled", cancelResult) emitPaymentResult(cancelResult) } } } } private fun createPaymentResult(payment: Payment): Map { return mapOf( "status" to when (payment.paymentStatus) { Payment.StatusCodes.APPROVED -> "approved" Payment.StatusCodes.REJECTED -> "rejected" Payment.StatusCodes.PENDING -> "pending" Payment.StatusCodes.IN_PROCESS -> "in_process" else -> "rejected" }, "paymentId" to payment.id.toString(), "statusDetail" to payment.statusDetail ?: "", "paymentData" to mapOf( "transactionAmount" to (payment.transactionAmount ?: 0.0), "currency" to (payment.currencyId ?: "ARS"), "description" to (payment.description ?: "") ) ) } private fun createErrorResult(error: MercadoPagoError): Map { return mapOf( "status" to "rejected", "paymentId" to "", "statusDetail" to error.message ?: "Unknown error", "error" to mapOf( "message" to (error.message ?: "Unknown error"), "code" to (error.errorCode ?: "UNKNOWN") ) ) } private fun createCancelResult(): Map { return mapOf( "status" to "rejected", "paymentId" to "", "statusDetail" to "Payment cancelled by user", "error" to mapOf( "message" to "Payment cancelled by user", "code" to "CANCELLED" ) ) } private fun emitPaymentResult(result: Map) { moduleRegistry?.getModule(EventEmitter::class.java)?.emit("onPaymentResult", result) } companion object { private const val REQUEST_CODE = 1234 } }