package com.stove.unity

import androidx.annotation.Keep
import com.stove.base.json.putIgnoreException
import com.stove.base.log.Logger
import com.stove.base.result.Result
import com.stove.view.View
import com.stove.view.ViewRequest
import com.stove.view.ViewUI
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 ViewWrapper {
    private const val TAG = "ViewWrapper"
    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 UserInfoKey = "userInfo"
    private const val ViewRequestsKey = "viewRequests"

    @JvmStatic
    fun fetchPopup(identifier: String) {
        fetchPopupInternal(null, identifier)
    }

    @JvmStatic
    fun fetchPopup(location: Int, identifier: String) {
        fetchPopupInternal(location, identifier)
    }

    private fun fetchPopupInternal(location: Int?, identifier: String) {
        val context = UnityPlayer.currentActivity.applicationContext
        View.fetchPopup(context, location) { result: Result, list: List<ViewRequest> ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            valueJSONObject.putIgnoreException(ViewRequestsKey, makeViewRequestJSONArray(list))

            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    /**
     * @since 2.1.0
     */
    @JvmStatic
    fun fetchNews(identifier: String) {
        val context = UnityPlayer.currentActivity.applicationContext
        View.fetchNews(context) { result: Result, list: List<ViewRequest> ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            valueJSONObject.putIgnoreException(ViewRequestsKey, makeViewRequestJSONArray(list))

            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

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

    @JvmStatic
    fun news(identifier: String) {
        val activity = UnityPlayer.currentActivity
        ViewUI.news(activity) { result: Result, map: Map<String, String> ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(UserInfoKey, convert(map))
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun customerSupport(identifier: String) {
        val activity = UnityPlayer.currentActivity
        ViewUI.customerSupport(activity) { result: Result, map: Map<String, String> ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(UserInfoKey, convert(map))
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun coupon(identifier: String) {
        val activity = UnityPlayer.currentActivity
        ViewUI.coupon(activity) { result: Result, map: Map<String, String> ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(UserInfoKey, convert(map))
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun community(identifier: String) {
        val activity = UnityPlayer.currentActivity
        ViewUI.community(activity) { result: Result, map: Map<String, String> ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(UserInfoKey, convert(map))
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }
    
    @JvmStatic
    fun communityWithURL(url: String, identifier: String) {
        val activity = UnityPlayer.currentActivity
        ViewUI.community(activity, url) { result: Result, map: Map<String, String> ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(UserInfoKey, convert(map))
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun popup(identifier: String) {
        popupInternal(null, identifier)
    }

    @JvmStatic
    fun popup(location: Int, identifier: String) {
        popupInternal(location, identifier)
    }

    private fun popupInternal(location: Int? = null, identifier: String) {
        val activity = UnityPlayer.currentActivity
        ViewUI.popup(activity, location) { result: Result, map: Map<String, String> ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(UserInfoKey, convert(map))
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun load(viewRequestString: String, identifier: String) {
        val activity = UnityPlayer.currentActivity
        val viewRequest = ViewRequest.from(viewRequestString)
        if (viewRequest == null) {
            Logger.trace(
                LogLevel.ERROR,
                "$TAG.load",
                logTagList("viewRequest is null")
            )
            return
        }
        ViewUI.load(activity, viewRequest) { result: Result, map: Map<String, String> ->
            val jsonObject = JSONObject()
            jsonObject.putIgnoreException(IdentifierKey, identifier)
            val valueJSONObject = JSONObject()
            valueJSONObject.putIgnoreException(UserInfoKey, convert(map))
            valueJSONObject.putIgnoreException(ResultKey, result.toJSONObject())
            jsonObject.putIgnoreException(ValueKey, valueJSONObject)
            val params = jsonObject.toString()
            UnityPlayer.UnitySendMessage(objectName, functionName, params)
        }
    }

    @JvmStatic
    fun useCoupon(code: String, identifier: String) {
        val activity = UnityPlayer.currentActivity

        View.useCoupon(activity.applicationContext, code) { 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 openExternalUrl(redirectUrl: String, identifier: String) {
        val activity = UnityPlayer.currentActivity
        
        ViewUI.openExternalBrowser(activity, redirectUrl) { 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(map: Map<String, String>): JSONObject {
        val jsonObject = JSONObject()
        map.forEach { entry ->
            jsonObject.putIgnoreException(entry.key, entry.value)
        }
        return jsonObject
    }

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