package com.tapjoy.easyapp

import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.ViewModel
import com.tapjoy.TJAwardCurrencyListener
import com.tapjoy.TJConnectListener
import com.tapjoy.TJEntryPoint
import com.tapjoy.TJError
import com.tapjoy.TJGetCurrencyBalanceListener
import com.tapjoy.TJLogLevel
import com.tapjoy.TJPlacement
import com.tapjoy.TJPlacementListener
import com.tapjoy.TJSetCurrencyAmountRequiredListener
import com.tapjoy.TJSetCurrencyBalanceListener
import com.tapjoy.TJSpendCurrencyListener
import com.tapjoy.Tapjoy
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import java.util.Hashtable

const val PREFERENCES = "easyapp"
const val PLACEMENT_NAME_KEY = "placementName"
const val DEBUG_KEY = "debugKey"
private const val TAG = "Main"

class MainViewModel : ViewModel() {

    private var examplePlacement: TJPlacement? = null
    private var offerwallPlacement: TJPlacement? = null

    private val _statusMessage = MutableStateFlow(if (Tapjoy.isConnected()) "Tapjoy SDK connected" else "Tapjoy SDK not connected")
    private val _currencyId = MutableStateFlow("")
    private val _currencyAmount = MutableStateFlow(10)
    private val _currencyBalance = MutableStateFlow(-1)
    private val _currencyRequiredAmount = MutableStateFlow(-1)
    private val _isConnecting = MutableStateFlow(false)
    private val _isConnected = MutableStateFlow(Tapjoy.isConnected())
    private val _isSelfManaged = MutableStateFlow(false)
    private val _isRequestReady = MutableStateFlow(false)
    private val _loggingLevel = MutableStateFlow(0)
    private val _purchasePrice = MutableStateFlow("0.99")
    private val _purchaseCode = MutableStateFlow("USD")

    val statusMessage = _statusMessage.asStateFlow()
    val currencyId = _currencyId.asStateFlow()
    val currencyAmount = _currencyAmount.asStateFlow()
    val currencyBalance = _currencyBalance.asStateFlow()
    val currencyRequiredAmount = _currencyRequiredAmount.asStateFlow()
    val isConnecting = _isConnecting.asStateFlow()
    val isConnected = _isConnected.asStateFlow()
    val isSelfManaged = _isSelfManaged.asStateFlow()
    val isRequestReady = _isRequestReady.asStateFlow()
    val loggingLevel = _loggingLevel.asStateFlow()
    val purchasePrice = _purchasePrice.asStateFlow()
    val purchaseCode = _purchaseCode.asStateFlow()

    val entryPoints = listOf("Not Set") + TJEntryPoint.entries
        .filter { it.value != null }
        .map {
            it.value.toString()
        }
    private var selectedEntryPoint: String? = null

    val loggingOptions = listOf("Error", "Warning", "Info", "Debug")

    fun connect(context: Context, sdkKey: String) {
        _isConnecting.value = true
        val connectFlags = Hashtable<String, Any>()
        // connectFlags[TapjoyConnectFlag.TJC_OPTION_LOGGING_LEVEL] = TJLogLevel.DEBUG
        // connectFlags[TapjoyConnectFlag.USER_ID] = "A_UNIQUE_USER_ID"
        Tapjoy.connect(
            context,
            sdkKey,
            connectFlags,
            object : TJConnectListener() {
                override fun onConnectSuccess() {
                    _isConnected.value = true
                    _isConnecting.value = false
                    _statusMessage.value = "Tapjoy SDK connected"
                    // NOTE: The get/spend/award currency methods will only work if your virtual currency is managed by Tapjoy.
                    Tapjoy.setEarnedCurrencyListener { currencyName, amount ->
                        _statusMessage.value = "You've just earned $amount $currencyName"
                    }
                    _loggingLevel.value = getLoggingLevel()
                }
                override fun onConnectFailure(code: Int, message: String?) {
                    _isConnected.value = false
                    _isConnecting.value = false
                    _statusMessage.value = "Tapjoy connect failed: $message Error code: $code"
                }

                override fun onConnectWarning(code: Int, message: String) {
                    _statusMessage.value = "Tapjoy connect succeeded with warning code: $code $message"
                }
            },
        )
    }

    fun showOfferwall() {
        offerwallPlacement = Tapjoy.getPlacement(
            "offerwall_unit",
            object : TJPlacementListener {
                override fun onRequestSuccess(placement: TJPlacement) {
                    _statusMessage.value = "onRequestSuccess for placement " + placement.name
                    if (!placement.isContentAvailable) {
                        _statusMessage.value = "No Offerwall content available"
                    }
                }
                override fun onRequestFailure(placement: TJPlacement, error: TJError) {
                    _statusMessage.value = "Offerwall error: " + error.message
                }
                override fun onContentReady(placement: TJPlacement) {
                    _statusMessage.value = "Offerwall request success"
                    placement.showContent()
                }
                override fun onContentShow(placement: TJPlacement) {
                    _statusMessage.value = "Offerwall onContentShow"
                }
                override fun onContentDismiss(placement: TJPlacement) {
                    _statusMessage.value = "Offerwall onContentDismiss"
                }
            },
        )
        offerwallPlacement?.requestContent()
    }

    fun requestPlacement(placementName: String) {
        examplePlacement = Tapjoy.getPlacement(
            placementName,
            object : TJPlacementListener {
                override fun onRequestSuccess(placement: TJPlacement) {
                    _statusMessage.value = "onRequestSuccess for placement " + placement.name
                    if (!placement.isContentAvailable) {
                        _statusMessage.value = "No content available for placement " + placement.name
                    }
                }

                override fun onRequestFailure(placement: TJPlacement, error: TJError) {
                    _statusMessage.value = "onRequestFailure for placement " + placement.name + " -- error: " + error.message
                }

                override fun onContentReady(placement: TJPlacement) {
                    _isRequestReady.value = true
                    _statusMessage.value = "onContentReady for placement " + placement.name
                }

                override fun onContentShow(placement: TJPlacement) {
                    _statusMessage.value = "onContentShow for placement " + placement.name
                }

                override fun onContentDismiss(placement: TJPlacement) {
                    _statusMessage.value = "onContentDismiss for placement: ${placement.name}"
                    _isRequestReady.value = false
                    // Best Practice: We recommend calling getCurrencyBalance as often as possible so the user's balance is always up-to-date.
                    Tapjoy.getCurrencyBalance(object : TJGetCurrencyBalanceListener {
                        override fun onGetCurrencyBalanceResponse(currencyName: String?, balance: Int) {
                            _statusMessage.value = "$currencyName: $balance"
                        }

                        override fun onGetCurrencyBalanceResponseFailure(error: String?) {
                            _statusMessage.value = "getCurrencyBalance error: $error"
                        }
                    })
                }
            },
        )

        if (isSelfManaged.value) {
            examplePlacement?.setCurrencyBalance(
                currencyId.value,
                currencyBalance.value,
                object : TJSetCurrencyBalanceListener {
                    override fun onSetCurrencyBalanceSuccess() {
                        Log.i(TAG, "Currency balance is set")
                    }

                    override fun onSetCurrencyBalanceFailure(code: Int, error: String) {
                        Log.i(TAG, "Currency balance failed: $error")
                    }
                },
            )
            examplePlacement?.setCurrencyAmountRequired(
                currencyId.value,
                currencyRequiredAmount.value,
                object : TJSetCurrencyAmountRequiredListener {
                    override fun onSetCurrencyAmountRequiredSuccess() {
                        Log.i(TAG, "Currency required is set")
                    }

                    override fun onSetCurrencyAmountRequiredFailure(code: Int, error: String) {
                        Log.i(TAG, "Currency required failed: $error")
                    }
                },
            )
        }

        if (selectedEntryPoint != null) {
            examplePlacement?.entryPoint = TJEntryPoint.fromString(selectedEntryPoint)
        }
        _statusMessage.value = "Requesting placement content"
        examplePlacement?.requestContent()
    }

    fun showPlacement() {
        examplePlacement?.showContent()
    }

    fun callSpendCurrency(amount: Int) {
        Tapjoy.spendCurrency(
            amount,
            object : TJSpendCurrencyListener {
                override fun onSpendCurrencyResponse(currencyName: String, balance: Int) {
                    _statusMessage.value = "$currencyName: $balance"
                }

                override fun onSpendCurrencyResponseFailure(error: String) {
                    _statusMessage.value = "spendCurrency error: $error"
                }
            },
        )
    }

    fun callAwardCurrency(amount: Int) {
        Tapjoy.awardCurrency(
            amount,
            object : TJAwardCurrencyListener {
                override fun onAwardCurrencyResponse(currencyName: String?, balance: Int) {
                    _statusMessage.value = "$currencyName: $balance"
                }
                override fun onAwardCurrencyResponseFailure(error: String?) {
                    _statusMessage.value = "awardCurrency error: $error"
                }
            },
        )
    }

    fun getCurrencyBalance() {
        Tapjoy.getCurrencyBalance(object : TJGetCurrencyBalanceListener {
            override fun onGetCurrencyBalanceResponse(currencyName: String?, balance: Int) {
                _statusMessage.value = "$currencyName: $balance"
            }
            override fun onGetCurrencyBalanceResponseFailure(error: String?) {
                _statusMessage.value = "getCurrencyBalance error: $error"
            }
        })
    }

    fun setCurrencyId(id: String) {
        _currencyId.value = id
    }

    fun setCurrencyRequiredAmount(amount: String) {
        _currencyRequiredAmount.value = amount.toIntOrNull() ?: -1
    }

    fun setCurrencyBalance(amount: String) {
        _currencyBalance.value = amount.toIntOrNull() ?: -1
    }

    fun setManagedCurrencyAmount(amount: String) {
        _currencyAmount.value = amount.toIntOrNull() ?: -1
    }

    fun setSelectedEntryPoint(entryPoint: String) {
        selectedEntryPoint = entryPoint
    }

    fun getEntryPointString(entryPoint: String): String {
        return entryPoint.replaceFirstChar(Char::titlecase)
            .replace("_", " ")
    }

    fun purchase() {
        val price = _purchasePrice.value.toDoubleOrNull() ?: 0.0
        val code = _purchaseCode.value
        Tapjoy.trackPurchase(code, price)
        _statusMessage.value = "Sent track purchase: ${_purchasePrice.value} $code"
    }

    fun setIsSelfManaged(selfManaged: Boolean) {
        _isSelfManaged.value = selfManaged
    }

    fun setManualConnectMessage() {
        _statusMessage.value = "Click Connect to Start"
    }

    fun getSDKVersion() = "SDK Version: " + Tapjoy.getVersion()

    fun setLoggingLevelSegment(index: Int) {
        _loggingLevel.value = index
    }

    fun setLoggingLevel(preferences: SharedPreferences, index: Int) {
        Tapjoy.setLoggingLevel(TJLogLevel.valueOf(index))
        // Use the getter to ensure the log level is not overridden by the server.
        val level = getLoggingLevel()
        setLoggingLevelSegment(level)
        preferences.edit().putInt(DEBUG_KEY, level).apply()
    }

    fun getStoredLoggingLevel(preferences: SharedPreferences): TJLogLevel {
        return TJLogLevel.valueOf(preferences.getInt(DEBUG_KEY, 0))
    }

    private fun getLoggingLevel(): Int {
        return Tapjoy.getLoggingLevel().getValue()
    }

    fun setPurchaseAmount(it: String) {
        _purchasePrice.value = it
    }

    fun setPurchaseCode(it: String) {
        _purchaseCode.value = it
    }
}
