package com.stove.unity

import androidx.annotation.Keep
import com.stove.auth.Provider
import com.stove.auth.termsofservice.TermsOfServiceData
import com.stove.auth.ui.AuthUI
import com.stove.auth.ui.operation.OperationUI
import com.stove.auth.ui.termsofservice.TermsOfServiceUI
import com.stove.base.json.putIgnoreException
import com.stove.base.log.Logger
import com.stove.base.result.Result
import com.unity3d.player.UnityPlayer
import org.json.JSONArray
import org.json.JSONException
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 AuthUIWrapper {
    private const val TAG = "AuthUIWrapper"
    private const val objectName = "StoveSDK"
    private const val functionName = "CallMessage"
    private const val IdentifierKey = "identifier"
    private const val ValueKey = "value"
    private const val ResultKey = "result"
    private const val AccessTokenKey = "accessToken"
    private const val TermsOfServiceDataListKey = "termsOfServiceDataList"
    private const val StateKey = "state"

    @JvmStatic
    fun handleResult(resultString: String, identifier: String) {
        val activity = UnityPlayer.currentActivity
        val result = Result.from(resultString)
        if (result == null) {
            Logger.trace(
                LogLevel.ERROR,
                "$TAG.handleResult",
                logTagList("result is null")
            )
            return
        }
        OperationUI.handleResult(activity, result) { hResult ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, hResult.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

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

    @JvmStatic
    fun setProviders(providerClassNameList: String) {
        try {
            val context = UnityPlayer.currentActivity.applicationContext
            val jsonArray = JSONArray(providerClassNameList)
            val providers = mutableListOf<Provider>()
            for (i in 0 until jsonArray.length()) {
                getProvider(jsonArray.getString(i))?.let {
                    providers.add(it)
                }
            }
            AuthUI.setProviders(context, providers)
        } catch (e: JSONException) {
            Logger.trace(
                LogLevel.ERROR,
                "$TAG.setProviders",
                exception = e
            )
        }
    }


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

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

    @JvmStatic
    fun agreeForRegisterProvider(className: String, identifier: String) {
        val activity = UnityPlayer.currentActivity
        val provider = getProvider(className)
        if (provider == null) {
            Logger.trace(
                LogLevel.ERROR,
                "$TAG.agreeForRegisterProvider",
                logTagList("provider is null")
            )
            return
        }
        TermsOfServiceUI.agreeForRegister(activity, provider) { result, list ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            valueJSONObject.putIgnoreException(TermsOfServiceDataListKey, makeTermsOfServiceData(list))
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun withdraw(identifier: String) {
        val activity = UnityPlayer.currentActivity
        AuthUI.withdraw(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)
        }
    }

    @JvmStatic
    fun link(identifier: String) {
        val activity = UnityPlayer.currentActivity
        AuthUI.link(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)
        }
    }

    @JvmStatic
    fun manageAccount(identifier: String) {
        val activity = UnityPlayer.currentActivity
        AuthUI.manageAccount(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)
        }
    }

    @JvmStatic
    fun manageDevices(identifier: String) {
        val activity = UnityPlayer.currentActivity
        AuthUI.manageDevices(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)
        }
    }

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

    @JvmStatic
    fun switchAccount(identifier: String) {
        val activity = UnityPlayer.currentActivity
        AuthUI.switchAccount(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 makeTermsOfServiceData(list: List<TermsOfServiceData>): JSONArray {
        val jsonArray = JSONArray()
        list.forEach {
            jsonArray.put(it.toJSONObject())
        }
        return jsonArray
    }

    private fun getProvider(providerClassName: String): Provider? {
        try {
            return Class.forName(providerClassName).newInstance() as Provider
        } catch (e: Exception) {
            Logger.trace(
                LogLevel.ERROR,
                "$TAG.getProvider",
                exception = e
            )
        }
        return null
    }

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


