package com.jiooption.trading.billing

import android.app.Activity
import android.util.Log
import com.android.billingclient.api.*
import com.jiooption.trading.utils.Constants
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow

/**
 * Google Play Billing manager
 * Handles billing client lifecycle, product queries, and purchase flows
 */
class BillingManager(private val activity: Activity) {

    companion object {
        private const val TAG = "BillingManager"
    }

    private var billingClient: BillingClient? = null
    private val _productDetailsList = MutableStateFlow<List<ProductDetails>>(emptyList())
    val productDetailsList = _productDetailsList.asStateFlow()

    private val _connectionState = MutableStateFlow(false)
    val connectionState = _connectionState.asStateFlow()

    var onPurchaseCompleted: ((Purchase) -> Unit)? = null
    var onPurchaseError: ((String) -> Unit)? = null

    /**
     * Initialize the billing client and connect
     */
    fun initialize() {
        billingClient = BillingClient.newBuilder(activity)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases(
                PendingPurchasesParams.newBuilder()
                    .enableOneTimeProducts()
                    .build()
            )
            .build()

        startConnection()
    }

    private fun startConnection() {
        billingClient?.startConnection(object : BillingClientStateListener {
            override fun onBillingSetupFinished(result: BillingResult) {
                if (result.responseCode == BillingClient.BillingResponseCode.OK) {
                    Log.d(TAG, "Billing client connected")
                    _connectionState.value = true
                    queryProducts()
                } else {
                    Log.e(TAG, "Billing setup failed: ${result.debugMessage}")
                    _connectionState.value = false
                }
            }

            override fun onBillingServiceDisconnected() {
                Log.w(TAG, "Billing service disconnected")
                _connectionState.value = false
                // Try to reconnect
                startConnection()
            }
        })
    }

    /**
     * Query available in-app products
     */
    fun queryProducts() {
        val productList = Constants.getProductIds().map { productId ->
            QueryProductDetailsParams.Product.newBuilder()
                .setProductId(productId)
                .setProductType(BillingClient.ProductType.INAPP)
                .build()
        }

        val params = QueryProductDetailsParams.newBuilder()
            .setProductList(productList)
            .build()

        billingClient?.queryProductDetailsAsync(params) { result, productDetailsList ->
            if (result.responseCode == BillingClient.BillingResponseCode.OK) {
                Log.d(TAG, "Found ${productDetailsList.size} products")
                _productDetailsList.value = productDetailsList
            } else {
                Log.e(TAG, "Product query failed: ${result.debugMessage}")
            }
        }
    }

    /**
     * Launch the Google Play purchase flow for a product
     */
    fun launchPurchaseFlow(productDetails: ProductDetails) {
        val flowParams = BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(
                listOf(
                    BillingFlowParams.ProductDetailsParams.newBuilder()
                        .setProductDetails(productDetails)
                        .build()
                )
            )
            .build()

        val result = billingClient?.launchBillingFlow(activity, flowParams)
        if (result?.responseCode != BillingClient.BillingResponseCode.OK) {
            Log.e(TAG, "Launch billing flow error: ${result?.debugMessage}")
            onPurchaseError?.invoke("Failed to launch purchase flow")
        }
    }

    /**
     * Launch purchase flow by product ID
     */
    fun purchaseProduct(productId: String) {
        val product = _productDetailsList.value.find { it.productId == productId }
        if (product != null) {
            launchPurchaseFlow(product)
        } else {
            onPurchaseError?.invoke("Product not found. Please try again.")
            // Refresh products
            queryProducts()
        }
    }

    /**
     * Listener for purchase updates
     */
    private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases ->
        when (billingResult.responseCode) {
            BillingClient.BillingResponseCode.OK -> {
                purchases?.forEach { purchase ->
                    handlePurchase(purchase)
                }
            }
            BillingClient.BillingResponseCode.USER_CANCELED -> {
                Log.d(TAG, "Purchase cancelled by user")
                onPurchaseError?.invoke("Purchase cancelled")
            }
            else -> {
                Log.e(TAG, "Purchase error: ${billingResult.debugMessage}")
                onPurchaseError?.invoke(billingResult.debugMessage ?: "Purchase failed")
            }
        }
    }

    /**
     * Handle a completed purchase
     */
    private fun handlePurchase(purchase: Purchase) {
        if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
            Log.d(TAG, "Purchase completed: ${purchase.orderId}")

            // Notify the calling code to verify server-side
            onPurchaseCompleted?.invoke(purchase)

            // Consume the purchase so it can be bought again (consumable)
            consumePurchase(purchase)
        } else if (purchase.purchaseState == Purchase.PurchaseState.PENDING) {
            Log.d(TAG, "Purchase pending: ${purchase.orderId}")
            onPurchaseError?.invoke("Purchase is pending. It will be processed shortly.")
        }
    }

    /**
     * Consume a purchase (required for consumable in-app products)
     */
    private fun consumePurchase(purchase: Purchase) {
        val consumeParams = ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.purchaseToken)
            .build()

        billingClient?.consumeAsync(consumeParams) { result, purchaseToken ->
            if (result.responseCode == BillingClient.BillingResponseCode.OK) {
                Log.d(TAG, "Purchase consumed successfully")
            } else {
                Log.e(TAG, "Consume error: ${result.debugMessage}")
            }
        }
    }

    /**
     * Get formatted price string for a product
     */
    fun getFormattedPrice(productId: String): String? {
        val product = _productDetailsList.value.find { it.productId == productId }
        return product?.oneTimePurchaseOfferDetails?.formattedPrice
    }

    /**
     * Clean up billing client
     */
    fun destroy() {
        billingClient?.endConnection()
        billingClient = null
    }
}
