package com.approagency.pharmacy.data.billing

import android.app.Activity
import android.content.Context
import com.approagency.pharmacy.BuildConfig
import com.approagency.pharmacy.data.local.SessionManager
import com.approagency.pharmacy.domain.billing.PurchaseGateway
import com.approagency.pharmacy.domain.billing.PurchaseResult
import com.approagency.pharmacy.domain.model.SubscriptionProduct
import ir.myket.billingclient.IabHelper
import ir.myket.billingclient.util.Purchase
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.util.UUID
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

/**
 * درگاهِ پرداختِ کافه‌بازار بر پایهٔ همان کتابخانهٔ `myket-billing-client`
 * (IabHelper). فروشگاهِ مقصد با `manifestPlaceholders` در build.gradle مشخص
 * می‌شود (com.farsitel.bazaar)، بنابراین کدِ IabHelper یکسان است و فقط مقصدِ
 * اتصال و کلیدِ عمومی فرق می‌کند.
 *
 * جریان:
 *  1. اتصال به سرویس بازار ([ensureSetup]).
 *  2. شروع خرید با SKU = [SubscriptionProduct.uuid] و دریافت توکنِ خرید.
 *  3. توکن به سرور فرستاده می‌شود (با gateway = "bazaar") و پس از تأیید، خرید
 *     [consume] می‌شود تا کاربر بتواند دورهٔ بعد دوباره خرید کند.
 *
 * چون IabHelper در هر لحظه فقط یک عملیاتِ ناهمگام را می‌پذیرد، همهٔ فراخوانی‌ها
 * با [mutex] ترتیبی می‌شوند.
 */
class BazaarPurchaseGateway(
    context: Context,
    private val session: SessionManager
) : PurchaseGateway {

    // مقدارِ معتبرِ درگاه در سمتِ سرورِ آپرواجنسی برای کافه‌بازار «cafe» است.
    override val name: String = "cafe"
    override val isAvailable: Boolean = true

    private val appContext = context.applicationContext
    private val mutex = Mutex()

    @Volatile private var helper: IabHelper? = null
    @Volatile private var setupDone = false

    /** خریدهای منتظرِ مصرف، برحسبِ توکن. */
    private val pending = mutableMapOf<String, Purchase>()

    override suspend fun purchase(
        activity: Activity,
        product: SubscriptionProduct
    ): Result<PurchaseResult> = mutex.withLock {
        val sku = product.uuid?.takeIf { it.isNotBlank() }
            ?: return Result.failure(IllegalArgumentException("شناسهٔ محصول (SKU) نامعتبر است."))

        ensureSetup().onFailure { return Result.failure(it) }
        val helper = helper ?: return Result.failure(IllegalStateException("اتصال به بازار برقرار نشد."))

        // developerPayload = شماره موبایلِ کاربر برای شناساییِ خریدار؛ در صورت نبود، توکن تصادفی.
        val payload = session.account.value.mobile?.takeIf { it.isNotBlank() }
            ?: UUID.randomUUID().toString()

        val outcome = runCatching {
            suspendCancellableCoroutine { cont ->
                // محصول‌های بازار از نوع «اشتراک» هستند.
                helper.launchSubscriptionPurchaseFlow(
                    activity,
                    sku,
                    IabHelper.OnIabPurchaseFinishedListener { result, purchase ->
                        when {
                            result.isSuccess && purchase != null ->
                                cont.resume(PurchaseOutcome.Success(purchase))
                            result.response == IabHelper.BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED ->
                                cont.resume(PurchaseOutcome.AlreadyOwned)
                            else ->
                                cont.resume(PurchaseOutcome.Error(result.message ?: "خطای پرداخت بازار"))
                        }
                    },
                    payload
                )
            }
        }.getOrElse { return Result.failure(it) }

        val purchase = when (outcome) {
            is PurchaseOutcome.Success -> outcome.purchase
            PurchaseOutcome.AlreadyOwned ->
                return Result.failure(IllegalStateException("اشتراک شما از قبل فعال است."))
            is PurchaseOutcome.Error -> return Result.failure(IllegalStateException(outcome.message))
        }

        val token = purchase.token
        if (token.isNullOrBlank()) {
            return Result.failure(IllegalStateException("توکن خرید دریافت نشد."))
        }
        pending[token] = purchase
        Result.success(PurchaseResult(purchaseToken = token, orderId = purchase.orderId))
    }

    // اشتراکِ کافه‌بازار مصرف نمی‌شود؛ این متد بی‌اثر است.
    override suspend fun consume(purchaseToken: String): Result<Unit> {
        pending.remove(purchaseToken)
        return Result.success(Unit)
    }

    /** اتصال به سرویس بازار (یک‌بار). */
    private suspend fun ensureSetup(): Result<Unit> {
        if (setupDone && helper != null) return Result.success(Unit)
        val newHelper = IabHelper(appContext, BuildConfig.IAB_PUBLIC_KEY)
            .apply { enableDebugLogging(BuildConfig.DEBUG) }
        return runCatching {
            suspendCancellableCoroutine { cont ->
                newHelper.startSetup(IabHelper.OnIabSetupFinishedListener { result ->
                    if (result.isSuccess) cont.resume(Unit)
                    else cont.resumeWithException(
                        IllegalStateException(result.message ?: "اتصال به بازار ناموفق بود")
                    )
                })
            }
        }.onSuccess {
            helper = newHelper
            setupDone = true
        }.onFailure {
            runCatching { newHelper.dispose() }
        }
    }

    private sealed interface PurchaseOutcome {
        data class Success(val purchase: Purchase) : PurchaseOutcome
        data object AlreadyOwned : PurchaseOutcome
        data class Error(val message: String) : PurchaseOutcome
    }
}
