package com.adealink.weparty.wallet.manager

import com.adealink.frame.base.CommonDataNullError
import com.adealink.frame.base.IError
import com.adealink.frame.base.Rlt
import com.adealink.frame.frame.BaseFrame
import com.adealink.weparty.App
import com.adealink.weparty.commonui.ext.isSuccess
import com.adealink.weparty.module.wallet.data.Currency
import com.adealink.weparty.wallet.datasource.remote.WalletHttpService
import com.adealink.weparty.wallet.recharge.data.ConvertCurrencyReq
import com.adealink.weparty.wallet.recharge.data.RechargeProduct
import kotlinx.coroutines.launch


val walletManager: IWalletManager by lazy { WalletManager() }

class WalletManager : BaseFrame<IWalletListener>(), IWalletManager {

    private val walletHttpService by lazy {
        App.instance.networkService.getHttpService(WalletHttpService::class.java)
    }

    private var coin: Double = 0.0
    private var diamond: Double = 0.0
    private var bean: Double = 0.0
    private var availableBean: Double = 0.0
    private var unsettledBean: Double = 0.0


    private val exchangeConfig = mutableMapOf<String, Double>()
    fun getExchangeKey(from: Currency, to: Currency): String {
        return "${from.type}_${to.type}"
    }

    override fun init() {
    }

    override fun getWalletData() {
        launch {
            notifyCurrencyChanged()
            notifyBeanChanged()
        }
    }

    override fun refreshWalletData() {
        launch {
            suspendRefreshWalletData()
        }
    }

    private suspend fun suspendRefreshWalletData() {
        pullWalletData()
        notifyCurrencyChanged()
        notifyBeanChanged()
    }

    override fun getBalance(currency: Currency): Double {
        return when (currency) {
            Currency.COIN -> coin
            Currency.DIAMOND -> diamond
            Currency.BEAN -> bean
        }
    }

    override suspend fun pullWalletData(): Rlt<Map<Currency, Double>> {
        val rlt = walletHttpService.pullWallet()
        when (rlt) {
            is Rlt.Failed -> {
                return rlt
            }

            is Rlt.Success -> {
                this.coin = rlt.data.data?.coin ?: 0.0
                this.diamond = rlt.data.data?.diamond ?: 0.0
                this.bean = rlt.data.data?.bean ?: 0.0
                this.availableBean = rlt.data.data?.availableBean ?: 0.0
                this.unsettledBean = rlt.data.data?.unsettledBean ?: 0.0
                return Rlt.Success(
                    mapOf(
                        Currency.COIN to this.coin,
                        Currency.DIAMOND to this.diamond,
                        Currency.BEAN to this.bean
                    )
                )
            }
        }
    }

    override suspend fun recharge(data: RechargeProduct): Rlt<Any> {
        return Rlt.Failed(IError(""))
    }

    override suspend fun loadConvertConfig(from: Currency, to: Currency): Rlt<Double> {
        val targetKey = getExchangeKey(from, to)
        var targetRatio = exchangeConfig[targetKey]
        if (targetRatio == null || targetRatio == 0.0) {
            val rlt = pullExchangeConfig()
            when (rlt) {
                is Rlt.Failed -> {
                    return rlt
                }

                is Rlt.Success -> {
                    //Ntd.
                }
            }
        }
        targetRatio = exchangeConfig[targetKey]
        return if (targetRatio == null || targetRatio == 0.0) {
            Rlt.Failed(CommonDataNullError())
        } else {
            Rlt.Success(targetRatio)
        }
    }

    private suspend fun pullExchangeConfig(): Rlt<Any> {
        val rlt = walletHttpService.getCurrencyExchangeConfig()
        when (rlt) {
            is Rlt.Failed -> {
                return rlt
            }

            is Rlt.Success -> {
                val configList = rlt.data.data?.config
                if (configList.isNullOrEmpty()) {
                    return Rlt.Failed(CommonDataNullError())
                }
                var coin_idr: Double? = null
                var diamond_idr: Double? = null
                var bean_idr: Double? = null
                for (config in configList) {
                    if (config.coin != null) {
                        runCatching {
                            coin_idr = config.coin / config.idr
                        }
                        continue
                    }
                    if (config.diamond != null) {
                        runCatching {
                            diamond_idr = config.diamond / config.idr
                        }
                        continue
                    }
                    if (config.bean != null) {
                        runCatching {
                            bean_idr = config.bean / config.idr
                        }
                        continue
                    }
                }

                exchangeConfig.clear()
                if (coin_idr != null && diamond_idr != null) {
                    runCatching {
                        exchangeConfig[getExchangeKey(Currency.COIN, Currency.DIAMOND)] =
                            coin_idr / diamond_idr
                        exchangeConfig[getExchangeKey(Currency.DIAMOND, Currency.COIN)] =
                            diamond_idr / coin_idr
                    }
                }
                if (coin_idr != null && bean_idr != null) {
                    runCatching {
                        exchangeConfig[getExchangeKey(Currency.COIN, Currency.BEAN)] =
                            coin_idr / bean_idr
                        exchangeConfig[getExchangeKey(Currency.BEAN, Currency.COIN)] =
                            bean_idr / coin_idr
                    }
                }
                if (bean_idr != null && diamond_idr != null) {
                    runCatching {
                        exchangeConfig[getExchangeKey(Currency.BEAN, Currency.DIAMOND)] =
                            bean_idr / diamond_idr
                        exchangeConfig[getExchangeKey(Currency.DIAMOND, Currency.BEAN)] =
                            diamond_idr / bean_idr
                    }
                }
                return rlt
            }
        }
    }

    override suspend fun convertTo(
        fromCurrency: Currency,
        toCurrency: Currency,
        amount: Double
    ): Rlt<Any> {
        val rlt = walletHttpService.convertCurrency(
            ConvertCurrencyReq(
                fromCurrency.type,
                toCurrency.type,
                amount
            )
        )
        if (rlt.isSuccess) {
            suspendRefreshWalletData()
        }
        return rlt
    }

    private fun notifyCurrencyChanged() {
        dispatch {
            it.onCurrencyChanged(
                mapOf(
                    Currency.COIN to this.coin,
                    Currency.DIAMOND to this.diamond,
                    Currency.BEAN to this.bean
                )
            )
        }
    }

    private fun notifyBeanChanged() {
        dispatch {
            it.onBeanChanged(bean, availableBean, unsettledBean)
        }
    }


}