package com.tangem.feature.wallet.presentation.wallet.state.transformers.converter

import com.tangem.common.ui.account.AccountCryptoPortfolioItemStateConverter
import com.tangem.common.ui.account.TokensListPortfolioItemConverter
import com.tangem.common.ui.tokens.TokenItemStateConverter
import com.tangem.core.ui.components.tokenlist.state.PortfolioItemContentUM
import com.tangem.core.ui.components.tokenlist.state.PortfolioTokensListItemUM
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.tokenlist.TokenList.GroupedByNetwork.NetworkGroup
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.impl.R
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
import com.tangem.common.ui.tokens.TokenConverterParams
import com.tangem.common.ui.tokens.TokenItemGrouping.toGroupedItems
import com.tangem.common.ui.tokens.TokenItemGrouping.toUngroupedItems
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.toPersistentList
import java.math.BigDecimal
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState.OrganizeTokensButtonConfig as WalletOrganizeTokensButtonConfig

@Suppress("LongParameterList")
internal class TokenListStateConverter(
    private val appCurrency: AppCurrency,
    private val params: TokenConverterParams,
    private val selectedWallet: UserWallet,
    private val clickIntents: WalletClickIntents,
    private val yieldModuleApyMap: Map<String, BigDecimal>,
    private val stakingAvailabilityMap: Map<CryptoCurrency, StakingAvailability>,
    shouldShowMainPromo: Boolean,
) : Converter<WalletTokensListState, WalletTokensListState> {

    private val yieldSupplyPromoBannerConverter = YieldSupplyPromoBannerConverter(
        yieldModuleApyMap,
        shouldShowMainPromo,
    )

    private val onTokenClick: (accountId: AccountId, currencyStatus: CryptoCurrencyStatus) -> Unit =
        { accountId, currencyStatus ->
            clickIntents.onTokenItemClick(accountId, currencyStatus)
        }

    private val onTokenLongClick: (accountId: AccountId, currencyStatus: CryptoCurrencyStatus) -> Unit =
        { accountId, currencyStatus ->
            clickIntents.onTokenItemLongClick(accountId, currencyStatus)
        }

    private fun tokenStatusConverter(accountId: AccountId) = TokenItemStateConverter(
        appCurrency = appCurrency,
        yieldModuleApyMap = yieldModuleApyMap,
        promoCryptoCurrencyStatus = yieldSupplyPromoBannerConverter.convert(params),
        stakingApyMap = stakingAvailabilityMap,
        onItemClick = { _, status -> onTokenClick(accountId, status) },
        onItemLongClick = { _, status -> onTokenLongClick(accountId, status) },
        onYieldPromoCloseClick = clickIntents::onYieldPromoCloseClick,
        onYieldPromoShown = clickIntents::onYieldPromoShown,
        onYieldPromoClicked = { status, apy -> clickIntents.onYieldPromoClicked(accountId, status, apy) },
    )

    override fun convert(value: WalletTokensListState): WalletTokensListState {
        return when (params) {
            is TokenConverterParams.Account -> convertAccountList(params)
            is TokenConverterParams.Wallet -> convertTokenList(
                tokenConverter = tokenStatusConverter(params.mainAccount.accountId),
                tokenList = params.tokenList,
            )
        }
    }

    private fun convertTokenList(tokenConverter: TokenItemStateConverter, tokenList: TokenList): WalletTokensListState =
        when (tokenList) {
            is TokenList.Empty -> WalletTokensListState.Empty
            is TokenList.GroupedByNetwork -> WalletTokensListState.ContentState.Content(
                items = tokenList.toGroupedItems(tokenConverter).toPersistentList(),
                organizeTokensButtonConfig = getOrganizeTokensButtonState(tokenList = tokenList),
            )
            is TokenList.Ungrouped -> WalletTokensListState.ContentState.Content(
                items = tokenList.toUngroupedItems(tokenConverter).toPersistentList(),
                organizeTokensButtonConfig = getOrganizeTokensButtonState(tokenList = tokenList),
            )
        }

    private fun convertAccountList(params: TokenConverterParams.Account): WalletTokensListState {
        val accountList = params.accountList

        fun AccountStatus.CryptoPortfolio.map(): TokensListItemUM.Portfolio {
            val tokenList: TokenList = this.tokenList
            val account: Account.CryptoPortfolio = this.account
            val isExtend = params.expandedAccounts.contains(account.accountId)
            val onItemClick: (Account.CryptoPortfolio) -> Unit = {
                if (isExtend) {
                    clickIntents.onAccountCollapseClick(it)
                } else {
                    clickIntents.onAccountExpandClick(it)
                }
            }
            val converter = AccountCryptoPortfolioItemStateConverter(
                appCurrency = appCurrency,
                account = account,
                onItemClick = onItemClick,
                priceChangeLce = this.priceChangeLce,
            )
            val accountItem = converter.convert(tokenList.totalFiatBalance)
            val tokenConverter = tokenStatusConverter(account.accountId)
            val tokensListState = convertTokenList(tokenConverter, tokenList)
            val items = when (tokensListState) {
                is WalletTokensListState.ContentState.PortfolioContent -> tokensListState.items
                is WalletTokensListState.ContentState.Content -> tokensListState.items
                is WalletTokensListState.ContentState.Loading -> tokensListState.items
                is WalletTokensListState.ContentState.Locked -> tokensListState.items
                is WalletTokensListState.Empty -> listOf()
            }
            val onEmptyAction = PortfolioItemContentUM.Empty.Action(
                text = resourceReference(id = R.string.onboarding_add_tokens),
                onClick = { clickIntents.onManageTokensClick(account.accountId) },
            )
            return TokensListPortfolioItemConverter(
                tokenItemUM = accountItem,
                isExpanded = isExtend,
                isCollapsable = true,
                tokens = items.filterIsInstance<PortfolioTokensListItemUM>().toPersistentList(),
                onEmptyAction = onEmptyAction,
            ).convert(Unit)
        }

        val accountItems = accountList.accountStatuses
            .filterCryptoPortfolio()
            .map { accountStatus ->
                when (accountStatus) {
                    is AccountStatus.CryptoPortfolio -> accountStatus.map()
                }
            }
        return WalletTokensListState.ContentState.PortfolioContent(
            items = accountItems.toPersistentList(),
            organizeTokensButtonConfig = getOrganizeTokensButtonStateV2(accountList = accountList),
        )
    }

    private fun getOrganizeTokensButtonState(tokenList: TokenList): WalletOrganizeTokensButtonConfig? {
        val currenciesSize = when (tokenList) {
            TokenList.Empty -> return null
            is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies).size
            is TokenList.Ungrouped -> tokenList.currencies.size
        }
        return if (currenciesSize > 1 && !isSingleCurrencyWalletWithToken()) {
            WalletOrganizeTokensButtonConfig(
                textRes = organizeButtonTextRes(),
                iconRes = organizeButtonIconRes(),
                isEnabled = tokenList.totalFiatBalance !is TotalFiatBalance.Loading,
                onClick = clickIntents::onOrganizeTokensClick,
            )
        } else {
            null
        }
    }

    private fun getOrganizeTokensButtonStateV2(accountList: AccountStatusList): WalletOrganizeTokensButtonConfig? {
        return if (!isSingleCurrencyWalletWithToken()) {
            WalletOrganizeTokensButtonConfig(
                textRes = organizeButtonTextRes(),
                iconRes = organizeButtonIconRes(),
                isEnabled = accountList.totalFiatBalance !is TotalFiatBalance.Loading,
                onClick = clickIntents::onOrganizeTokensClick,
            )
        } else {
            null
        }
    }

    private fun organizeButtonTextRes(): Int = R.string.main_add_and_manage_tokens

    private fun organizeButtonIconRes(): Int = R.drawable.ic_filter_default_24

    private fun isSingleCurrencyWalletWithToken(): Boolean {
        return selectedWallet is UserWallet.Cold &&
            selectedWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()
    }
}