package com.remax.visualnovel.manager.pay

import android.app.Activity
import android.os.Handler
import android.os.Looper
import android.os.Message
import com.android.billingclient.api.AcknowledgePurchaseParams
import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingClientStateListener
import com.android.billingclient.api.BillingFlowParams
import com.android.billingclient.api.BillingFlowParams.SubscriptionUpdateParams.ReplacementMode
import com.android.billingclient.api.BillingResult
import com.android.billingclient.api.ConsumeParams
import com.android.billingclient.api.ProductDetails
import com.android.billingclient.api.Purchase
import com.android.billingclient.api.PurchasesUpdatedListener
import com.android.billingclient.api.QueryProductDetailsParams
import com.android.billingclient.api.QueryPurchasesParams
import com.remax.visualnovel.R
import com.remax.visualnovel.api.factory.ServiceFactory
import com.remax.visualnovel.app.base.BaseBindingActivity
import com.remax.visualnovel.app.base.app.CommonApplicationProxy
import com.remax.visualnovel.constant.StatusCode
import com.remax.visualnovel.entity.request.ChargeProduct
import com.remax.visualnovel.entity.request.ValidateTransactionDTO
import com.remax.visualnovel.entity.response.SubPrice
import com.remax.visualnovel.entity.response.base.parseData
import com.remax.visualnovel.extension.launchFlow
import com.remax.visualnovel.repository.api.PayRepository
import com.remax.visualnovel.ui.wallet.manager.WalletManager
import com.remax.visualnovel.utils.TimeUtils
import com.remax.visualnovel.utils.analytics.AnalyticsUtils
import com.google.gson.Gson
import com.pengxr.modular.eventbus.generated.events.EventDefineOfWalletEvents
import com.remax.visualnovel.configs.NovelApplication
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import timber.log.Timber
import java.math.BigDecimal
import java.math.RoundingMode

/**
 * Created by HJW on 2022/6/28
 */
object GooglePayManager : PurchasesUpdatedListener {

    private val payRepository by lazy {
        PayRepository(ServiceFactory.createService())
    }

    private var isConnected = false

    private var billingClient: BillingClient? = null

    private var queryProductTime = 0L

    var productDetails = listOf<ProductDetails?>()
        private set
    var subProductDetails: MutableList<ProductDetails> = arrayListOf()
        private set

    private val mHandler: Handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            if (msg.what == 100) {
                queryPurchases()
            }
        }
    }

    fun startConnection(callback: () -> Unit, errorCallback: (() -> Unit)? = null) {
        if (billingClient == null) {
            billingClient =
                BillingClient.newBuilder(CommonApplicationProxy.application).enablePendingPurchases().setListener(this)
                    .build()
        }
        if (isConnected && billingClient?.isReady == true) {
            Timber.d("Google Play正常连接")
            callback.invoke()
        } else {
            billingClient?.startConnection(object : BillingClientStateListener {
                override fun onBillingSetupFinished(billingResult: BillingResult) {
                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                        isConnected = true
                        callback.invoke()
                    } else {
                        isConnected = false
                        errorCallback?.invoke()
                        Timber.e("GooglePay连接失败")
                    }
                }

                override fun onBillingServiceDisconnected() {
                    isConnected = false
                    // Try to restart the connection on the next request to
                    // Google Play by calling the startConnection() method.
                    Timber.e("GooglePay断开连接")
                }
            })
        }
    }

    /**
     * 检查本地商品是否为空
     */
    fun checkProductDetails() {
        startConnection({
            /**
             * 如果距离上次查询时间超过10分钟，则清空重新查询，防止商品token过期
             */
            if (System.currentTimeMillis() - queryProductTime > 10 * TimeUtils.ONE_MINUTE) {
                queryProductTime = System.currentTimeMillis()
                queryAllProductDetails()
            } else {
                if (productDetails.isEmpty()) {
                    queryAllProductDetails(isSubs = false)
                }
                if (subProductDetails.isEmpty()) {
                    queryAllProductDetails(isConsume = false)
                }
            }
        })
    }

    private var productList = arrayListOf<ChargeProduct>()
    private var subList = arrayListOf<SubPrice>()

    private fun queryProductDetails() {
        val immutableList = arrayListOf<QueryProductDetailsParams.Product>()
        productList.forEach { product ->
            immutableList.add(
                QueryProductDetailsParams.Product.newBuilder()
                    .setProductId(product.productId)
                    .setProductType(BillingClient.ProductType.INAPP)
                    .build()
            )
        }
        if (immutableList.isNotEmpty()) {
            val queryProductDetailsParams = QueryProductDetailsParams.newBuilder()
                .setProductList(immutableList)
                .build()
            billingClient?.queryProductDetailsAsync(
                queryProductDetailsParams
            ) { billingResult, productDetailsList ->
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    productDetailsList.forEach {
                        Timber.d("GooglePay 查询一次性商品本地化 : $it")
                    }
                    productDetails = productDetailsList
                    queryPurchases()
                }
            }
        }
    }

    private fun querySubProductDetails() {
        val immutableList = arrayListOf<QueryProductDetailsParams.Product>()
        subList.forEach { product ->
            immutableList.add(
                QueryProductDetailsParams.Product.newBuilder()
                    .setProductId(product.productId)
                    .setProductType(BillingClient.ProductType.SUBS)
                    .build()
            )
        }
        if (immutableList.isNotEmpty()) {
            val queryProductDetailsParams = QueryProductDetailsParams.newBuilder()
                .setProductList(immutableList)
                .build()
            billingClient?.queryProductDetailsAsync(
                queryProductDetailsParams
            ) { billingResult, productDetailsList ->
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    productDetailsList.forEach {
                        Timber.d("GooglePay 查询订阅商品本地化 : $it")
                    }
                    subProductDetails.clear()
                    subProductDetails.addAll(productDetailsList)
                }
            }
        }
    }

    /**
     * 查询所有商品
     */
     fun queryAllProductDetails(isConsume: Boolean = true, isSubs: Boolean = true) {
        if (isConsume) {
            CoroutineScope(Dispatchers.Main).launch {
                launchFlow({
                    payRepository.getProducts()
                }).collect {
                    it.parseData({
                        onSuccess = { productInfo ->
                            productList.clear()
                            productList.addAll(productInfo?.productList ?: emptyList())
                            queryProductDetails()
                        }

                        onFailed = { _, errorMsg ->
                            Timber.e("GooglePay google支付单例查询充值接口报错 msg:${errorMsg}")
                        }
                    })
                }
            }
        }

        if (isSubs) {
            CoroutineScope(Dispatchers.Main).launch {
                launchFlow({
                    payRepository.getSubPriceList()
                }).collect {
                    it.parseData({
                        onSuccess = { group ->
                            subList.clear()
                            subList.addAll(group?: emptyList())
                            querySubProductDetails()
                        }

                        onFailed = { _, errorMsg ->
                            Timber.e("GooglePay google支付单例查询订阅商品接口报错 msg:${errorMsg}")
                        }
                    })
                }
            }
        }
    }

    /**
     * 发起支付
     */
    fun pay(
        activity: Activity,
        productId: String,
        isSub: Boolean = false,
        oldPurchaseToken: String = "",
        tradeNo: String = "",
        errorCallback: (() -> Unit)? = null
    ) {
        startConnection({
            queryProductDetails(
                activity,
                productId,
                if (isSub) BillingClient.ProductType.SUBS else BillingClient.ProductType.INAPP,
                oldPurchaseToken,
                tradeNo,
                errorCallback
            )
        }) {
            errorCallback?.invoke()
        }
    }

    /**
     * 查询商品
     */
    private fun queryProductDetails(
        activity: Activity,
        productId: String,
        type: String,
        oldPurchaseToken: String = "",
        tradeNo: String = "",
        errorCallback: (() -> Unit)? = null
    ) {
        val queryProductDetailsParams =
            QueryProductDetailsParams.newBuilder()
                .setProductList(
                    arrayListOf(
                        QueryProductDetailsParams.Product.newBuilder()
                            .setProductId(productId)
                            .setProductType(type)
                            .build()
                    )
                )
                .build()

        billingClient?.queryProductDetailsAsync(
            queryProductDetailsParams
        ) { billingResult, productDetailsList ->
            // check billingResult
            if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
                Timber.e("GooglePay queryProductDetailsAsync onFailed")
                errorCallback?.invoke()
            } else {
                /**
                 * 启动购买流程
                 */
                productDetailsList.forEach { productDetails ->
                    val flowParamsBuilder = BillingFlowParams.ProductDetailsParams.newBuilder()
                        // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
                        .setProductDetails(productDetails)
                    if (type == BillingClient.ProductType.SUBS) {
                        val offerToken = productDetails?.subscriptionOfferDetails?.get(0)?.offerToken ?: ""
                        flowParamsBuilder.setOfferToken(offerToken)
                    }
                    val flowParams = flowParamsBuilder.build()
                    val billingFlowParamsBuilder =
                        BillingFlowParams.newBuilder().setProductDetailsParamsList(arrayListOf(flowParams))
                    if (type == BillingClient.ProductType.SUBS && oldPurchaseToken.isNotEmpty()) {
                        billingFlowParamsBuilder.setSubscriptionUpdateParams(
                            BillingFlowParams.SubscriptionUpdateParams.newBuilder()
                                // purchaseToken can be found in Purchase#getPurchaseToken
                                .setOldPurchaseToken(oldPurchaseToken)
                                .setSubscriptionReplacementMode(ReplacementMode.DEFERRED)
//                                .setReplaceProrationMode(BillingFlowParams.ProrationMode.DEFERRED)
                                .build()
                        )
                    }
                    val billingFlowParams = billingFlowParamsBuilder
                        .setObfuscatedAccountId(tradeNo)
                        .setObfuscatedProfileId(tradeNo)
                        .build()
                    // Launch the billing flow
                    val billingFlowParamsResult = billingClient?.launchBillingFlow(activity, billingFlowParams)
                    if (billingFlowParamsResult?.responseCode != BillingClient.BillingResponseCode.OK) {
                        Timber.e("GooglePay launchBillingFlow onFailed")
                        errorCallback?.invoke()
                    }
                }
            }
        }
    }

    /**
     * 将购买操作的结果传送给实现 PurchasesUpdatedListener 接口的监听器
     */
    override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
        Timber.d("GooglePay 购买操作结果回调 billingResult:$billingResult res:${Gson().toJson(purchases)} ")
        when {
            billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null -> {
                queryPurchases()
            }

            billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED -> {
                //取消购买
            }

            else -> {
//                showError()
            }
        }
    }

    /**
     * 查询购买交易记录
     */
    fun queryPurchases() {
        startConnection({
            billingClient?.queryPurchasesAsync(
                QueryPurchasesParams.newBuilder()
                    .setProductType(BillingClient.ProductType.INAPP)
                    .build()
            ) { billingResult, purchases ->
                Timber.d("GooglePay 查询一次性消费商品 billingResult:$billingResult res:$purchases} ")
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    if (purchases.isNotEmpty()) {
                        purchases.forEach {
                            handlePurchase(it, BillingClient.ProductType.INAPP)
                        }
                    }
                }
            }

            billingClient?.queryPurchasesAsync(
                QueryPurchasesParams.newBuilder()
                    .setProductType(BillingClient.ProductType.SUBS)
                    .build()
            ) { billingResult, purchases ->
                Timber.d("GooglePay 查询订阅商品 billingResult:$billingResult res:${Gson().toJson(purchases)} ")
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases.isNotEmpty()) {
                    for (purchase in purchases) {
                        handlePurchase(purchase, BillingClient.ProductType.SUBS)
                    }
                }
            }
        })
    }

    /**
     * 处理消费
     */
    private fun handlePurchase(purchase: Purchase, type: String) {
        if (!purchase.isAcknowledged) {
            //订阅
            if (type == BillingClient.ProductType.SUBS) {
                val build = AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.purchaseToken)
                    .build()
                billingClient?.acknowledgePurchase(build) { billingResult ->
                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                        //订阅成功
                        EventDefineOfWalletEvents.onGoogleSubSucceeded().post(purchase.purchaseToken)
                    }
                }
            }
            //一次性消费
            else {
                val consumeParams = ConsumeParams.newBuilder()
                    .setPurchaseToken(purchase.purchaseToken)
                    .build()
                billingClient?.consumeAsync(consumeParams) { billingResult, purchaseToken ->
                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                        //消费成功
                        try {
                            var currency = "USD"
                            var price = 0.00
                            productDetails.find { it?.productId == purchase.products[0] }?.let { productDetails ->
                                currency = productDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode ?: "USD"
                                price =
                                    BigDecimal(
                                        productDetails.oneTimePurchaseOfferDetails?.priceAmountMicros ?: 0L
                                    ).divide(
                                        BigDecimal(1000000),
                                        2,
                                        RoundingMode.DOWN
                                    ).setScale(2, BigDecimal.ROUND_DOWN).toDouble()
                            }
                            val orderId = purchase.orderId
                            val productId = purchase.products[0]
                            Timber.d("GooglePay 本次消费的数据 orderId:$orderId productId:$productId currency:$currency price:$price")
                            validateToken(purchaseToken, productId, orderId, currency, price)
                        } catch (e: Exception) {
                            Timber.e("GooglePay 消费回调报错 msg:${e.localizedMessage}")
                        }
                    } else {
                        //消费失败, 后面查询消费记录后再次消费，否则，就只能等待退款
                        Timber.d("GooglePay consumeAsync failed")
                        mHandler.removeMessages(100)
                        mHandler.sendEmptyMessageDelayed(100, TimeUtils.ONE_MINUTE)
                    }
                }
            }
        }
    }

    /**
     * 后端入账，并且查询钱包
     * 验证支付结果, 如果成功, 则服务器端增加buff
     */
    private fun validateToken(
        purchaseToken: String,
        productId: String,
        orderId: String?,
        currency: String,
        price: Double
    ) {
        val currActivity = NovelApplication.getCurrentActivity()
        val dto = ValidateTransactionDTO(productId, purchaseToken)
        CoroutineScope(Dispatchers.IO).launch {
            launchFlow({
                payRepository.validateTranslation(dto)
            }, {
                (currActivity as? BaseBindingActivity<*>)?.showLoading()
            }) {
                (currActivity as? BaseBindingActivity<*>)?.hideLoading()
            }.collect {
                it.parseData({
                    onSuccess = {
                        (currActivity as? BaseBindingActivity<*>)?.showToast(R.string.charge_succeeded)
                        AnalyticsUtils.logAnalytics("Charge_CheckOut_Success")
                        //充值成功通知
                        EventDefineOfWalletEvents.chargeSucceeded().post(null)
                        WalletManager.refreshWallet()
                    }

                    onFailed = { errorCode, _ ->
                        if (errorCode == StatusCode.UNUSED_PURCHASE_TOKEN.code) {
                            WalletManager.refreshWallet()
                        }
                    }
                })
            }
        }
    }

}