package com.tangem.features.send.feeselector.model.transformers

import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeExtraInfo
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeFiatRateUM
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeItem
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeNonce
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeSelectorUM
import com.tangem.features.send.api.subcomponents.feeSelector.params.FeeSelectorParams
import com.tangem.features.send.feeselector.model.FeeSelectorIntents
import com.tangem.features.send.feeselector.model.FeeSelectorLogic
import com.tangem.lib.crypto.BlockchainUtils.isTron
import com.tangem.utils.transformer.Transformer
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList

@Suppress("LongParameterList")
internal class FeeSelectorLoadedTransformer(
    private val cryptoCurrencyStatus: CryptoCurrencyStatus,
    private val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
    private val appCurrency: AppCurrency,
    private val fees: FeeSelectorLogic.LoadedFeeResult,
    private val feeStateConfiguration: FeeSelectorParams.FeeStateConfiguration,
    private val isFeeApproximate: Boolean,
    private val feeSelectorIntents: FeeSelectorIntents,
    private val shouldDisableCustomFee: Boolean,
) : Transformer<FeeSelectorUM> {

    private val feeItemsConverter = FeeItemConverter(
        feeStateConfiguration = feeStateConfiguration,
        normalFee = fees.transactionFee.normal,
        feeSelectorIntents = feeSelectorIntents,
        appCurrency = appCurrency,
        cryptoCurrencyStatus = feeCryptoCurrencyStatus,
        shouldDisableCustomFee = shouldDisableCustomFee,
    )

    override fun transform(prevState: FeeSelectorUM): FeeSelectorUM {
        val prevCustomFee = if (prevState is FeeSelectorUM.Content) {
            prevState.feeItems.find { it is FeeItem.Custom } as? FeeItem.Custom
        } else {
            null
        }

        val feeItems: ImmutableList<FeeItem> = feeItemsConverter.convert(
            FeeItemConverter.Input(fees.transactionFee, prevCustomFee),
        )

        val selectedFee = when (prevState) {
            is FeeSelectorUM.Content -> if (prevState.selectedFeeItem is FeeItem.Loading) {
                feeItems.firstOrNull { it is FeeItem.Market }
            } else {
                feeItems.firstOrNull { it.isSameClass(prevState.selectedFeeItem) }
            } ?: FeeItem.Loading
            is FeeSelectorUM.Error,
            FeeSelectorUM.Loading,
            -> feeItems.find { it is FeeItem.Suggested } ?: feeItems.first { it is FeeItem.Market }
        }

        val nonce = ((prevState as? FeeSelectorUM.Content)?.feeNonce as? FeeNonce.Nonce)?.nonce

        return FeeSelectorUM.Content(
            isPrimaryButtonEnabled = selectedFee !is FeeItem.Loading,
            fees = fees.transactionFee,
            feeItems = feeItems,
            selectedFeeItem = selectedFee,
            feeExtraInfo = FeeExtraInfo(
                isFeeApproximate = isFeeApproximate,
                isFeeConvertibleToFiat = feeCryptoCurrencyStatus.currency.network.hasFiatFeeRate,
                isTronToken = cryptoCurrencyStatus.currency is CryptoCurrency.Token &&
                    isTron(cryptoCurrencyStatus.currency.network.rawId),
                feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
                availableFeeCurrencies = getAvailableFeeCurrencies(),
                transactionFeeExtended = (fees as? FeeSelectorLogic.LoadedFeeResult.Extended)?.fee,
            ),
            feeFiatRateUM = feeCryptoCurrencyStatus.value.fiatRate?.let { rate ->
                FeeFiatRateUM(
                    rate = rate,
                    appCurrency = appCurrency,
                )
            },
            feeNonce = if (fees.transactionFee.normal is Fee.Ethereum) {
                FeeNonce.Nonce(
                    nonce = nonce,
                    onNonceChange = feeSelectorIntents::onNonceChange,
                )
            } else {
                FeeNonce.None
            },
        )
    }

    private fun getAvailableFeeCurrencies(): ImmutableList<CryptoCurrencyStatus>? {
        if (fees !is FeeSelectorLogic.LoadedFeeResult.Extended) return null
        return fees.availableTokens.toImmutableList()
    }
}