package com.stove.unity

import androidx.annotation.Keep
import com.stove.base.json.putIgnoreException
import com.stove.base.log.Logger
import com.stove.iap.Optional
import com.stove.iap.Product
import com.stove.iap.google.Google
import com.unity3d.player.UnityPlayer
import org.json.JSONArray
import org.json.JSONObject
import com.stove.base.log.model.LogLevel
import com.stove.base.log.model.LogTag
import com.stove.base.log.model.logTagList

@Keep
object IAPGoogleWrapper {
    private const val TAG = "IAPGoogleWrapper"
    private const val objectName = "StoveSDK"
    private const val functionName = "CallMessage"
    private const val notifyFunctionName = "NotifyMessage"
    private const val IdentifierKey = "identifier"
    private const val ValueKey = "value"
    private const val ProductKey = "product"
    private const val ProductListKey = "productList"
    private const val PurchaseDetailKey = "purchaseDetail"
    private const val ResultKey = "result"
    private const val VoidedPurchasesKey = "voidedPurchases"

    private val google by lazy {
        Google(UnityPlayer.currentActivity)
    }

    private var products: List<Product> = emptyList()
    
    @JvmStatic
    fun setCustomBillingGUID(guid: String) {
        google.setCustomBillingGUID(guid)
    }

    @JvmStatic
    fun initialize(identifier: String) {
        IAPWrapper.setIAP(google)
        google.initialize { result ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun fetchProducts(identifier: String) {
        google.fetchProducts { result, products ->
            if (result.isSuccessful()) {
                this.products = products
            }
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            valueJSONObject.putIgnoreException(ProductListKey, convert(products))
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun setListener(identifier: String) {
        google.setListener { result, product, purchaseDetail ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            product?.let {
                valueJSONObject.putIgnoreException(ProductKey, product.toJSONObject())
            }
            purchaseDetail?.let {
                valueJSONObject.putIgnoreException(PurchaseDetailKey, purchaseDetail.toJSONObject())
            }
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)

            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, notifyFunctionName, params)
        }
    }

    @JvmStatic
    fun startPurchase(productString: String, identifier: String) {
        val activity = UnityPlayer.currentActivity
        val product = Product.from(productString)
        if (product == null) {
            Logger.trace(
                LogLevel.ERROR,
                "$TAG.startPurchase",
                logTagList("product is null")
            )
            return
        }

        google.startPurchase(activity, product) { result ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    @JvmOverloads
    fun startPurchaseWithOption(productString: String, serviceOrderId: String? = null, optionalString: String? = null, identifier: String) {
        val activity = UnityPlayer.currentActivity
        val product = Product.from(productString)
        if (product == null) {
            Logger.trace(
                LogLevel.ERROR,
                "$TAG.startPurchaseWithOption",
                logTagList("product is null")
            )
            return
        }

        val optional = optionalString?.let {
            Optional.from(optionalString)
        }

        google.startPurchase(activity, product, serviceOrderId, optional) { result ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun flush(): Boolean {
        return google.flush()
    }

    @JvmStatic
    fun consume(productString: String, identifier: String) {
        val product = Product.from(productString)
        if (product == null) {
            Logger.trace(
                LogLevel.ERROR,
                "$TAG.consume",
                logTagList("product is null")
            )
            return
        }

        google.consume(product) { result ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun fetchVoidedPurchases(identifier: String) {
        google.fetchVoidedPurchases { result, voidedPurchases ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            valueJSONObject.putIgnoreException(VoidedPurchasesKey, voidedPurchases)
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun handleVoidedPurchases(identifier: String) {
        val activity = UnityPlayer.currentActivity
        google.handleVoidedPurchases(activity) { result ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    private fun convert(list: List<Product>): JSONArray {
        val jsonArray = JSONArray()
        list.forEach {
            jsonArray.put(it.toJSONObject())
        }
        return jsonArray
    }

    @JvmStatic
    fun getVersion(): String? {
        val version : String? = com.stove.iap.google.BuildConfig.VERSION_NAME
        return version
    }
}