package com.tangem.features.swap.v2.impl.sendviaswap.confirm.model

import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.left
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.ui.amountScreen.converters.AmountReduceByTransformer
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.navigationButtons.NavigationButton
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.account.status.usecase.GetAccountCurrencyByAddressUseCase
import com.tangem.domain.express.models.ExpressOperationType
import com.tangem.domain.express.models.ExpressProviderType
import com.tangem.domain.express.models.ExpressRateType
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.isHotWallet
import com.tangem.domain.quotes.IsHighNetworkFeeUseCase
import com.tangem.domain.settings.IsSendTapHelpEnabledUseCase
import com.tangem.domain.swap.models.SwapAmountType
import com.tangem.domain.swap.models.SwapDirection.Companion.withSwapDirection
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.models.TransactionFeeExtended
import com.tangem.domain.transaction.usecase.EstimateFeeUseCase
import com.tangem.domain.transaction.usecase.gasless.EstimateFeeForGaslessTxUseCase
import com.tangem.domain.transaction.usecase.gasless.EstimateFeeForTokenUseCase
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.api.subcomponents.destination.entity.DestinationUM
import com.tangem.features.send.api.subcomponents.feeSelector.FeeSelectorReloadTrigger
import com.tangem.features.send.api.subcomponents.feeSelector.callbacks.FeeSelectorModelCallback
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeSelectorUM
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsComponent
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsComponent.Params.NotificationData
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsUpdateListener
import com.tangem.features.send.api.subcomponents.notifications.SendNotificationsUpdateTrigger
import com.tangem.features.swap.v2.api.SwapFeatureToggles
import com.tangem.features.swap.v2.api.subcomponents.SwapAmountUpdateTrigger
import com.tangem.features.swap.v2.impl.R
import com.tangem.features.swap.v2.impl.amount.SwapAmountReduceTrigger
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
import com.tangem.features.swap.v2.impl.amount.model.SwapAmountQuoteUtils
import com.tangem.features.swap.v2.impl.common.ConfirmData
import com.tangem.features.swap.v2.impl.common.SwapAlertFactory
import com.tangem.features.swap.v2.impl.common.SwapUtils.INCREASE_GAS_LIMIT_FOR_CEX
import com.tangem.features.swap.v2.impl.common.entity.ConfirmUM
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import com.tangem.features.swap.v2.impl.notifications.SwapNotificationsComponent.Params.SwapNotificationData
import com.tangem.features.swap.v2.impl.notifications.SwapNotificationsUpdateListener
import com.tangem.features.swap.v2.impl.notifications.SwapNotificationsUpdateTrigger
import com.tangem.features.swap.v2.impl.sendviaswap.SendWithSwapRoute
import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticEvents
import com.tangem.features.swap.v2.impl.sendviaswap.confirm.SendWithSwapConfirmComponent
import com.tangem.features.swap.v2.impl.sendviaswap.confirm.model.transformers.SendWithSwapConfirmInitialStateTransformer
import com.tangem.features.swap.v2.impl.sendviaswap.confirm.model.transformers.SendWithSwapConfirmSendingStateTransformer
import com.tangem.features.swap.v2.impl.sendviaswap.confirm.model.transformers.SendWithSwapConfirmSentStateTransformer
import com.tangem.features.swap.v2.impl.sendviaswap.confirm.model.transformers.SendWithSwapConfirmationNotificationsTransformer
import com.tangem.features.swap.v2.impl.sendviaswap.entity.SendWithSwapUM
import com.tangem.lib.crypto.BlockchainFeeUtils.patchTransactionFeeForSwap
import com.tangem.utils.coroutines.AppCoroutineScope
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.orZero
import jakarta.inject.Inject
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import java.math.BigDecimal
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeSelectorUM as FeeSelectorUMRedesigned
import com.tangem.utils.transformer.update as transformerUpdate

@Suppress("LongParameterList", "LargeClass")
@ModelScoped
internal class SendWithSwapConfirmModel @Inject constructor(
    override val dispatchers: CoroutineDispatcherProvider,
    private val router: Router,
    private val isSendTapHelpEnabledUseCase: IsSendTapHelpEnabledUseCase,
    private val estimateFeeUseCase: EstimateFeeUseCase,
    private val estimateFeeForTokenUseCase: EstimateFeeForTokenUseCase,
    private val estimateFeeForGaslessTxUseCase: EstimateFeeForGaslessTxUseCase,
    private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase,
    private val isHighNetworkFeeUseCase: IsHighNetworkFeeUseCase,
    private val swapFeatureToggles: SwapFeatureToggles,
    private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
    private val sendNotificationsUpdateTrigger: SendNotificationsUpdateTrigger,
    private val swapNotificationsUpdateTrigger: SwapNotificationsUpdateTrigger,
    private val sendNotificationsUpdateListener: SendNotificationsUpdateListener,
    private val swapNotificationsUpdateListener: SwapNotificationsUpdateListener,
    private val getAccountCurrencyByAddressUseCase: GetAccountCurrencyByAddressUseCase,
    private val swapAmountReduceTrigger: SwapAmountReduceTrigger,
    private val swapAmountUpdateTrigger: SwapAmountUpdateTrigger,
    private val feeSelectorReloadTrigger: FeeSelectorReloadTrigger,
    private val swapAlertFactory: SwapAlertFactory,
    private val analyticsEventHandler: AnalyticsEventHandler,
    private val appScope: AppCoroutineScope,
    swapTransactionSenderFactory: SwapTransactionSender.Factory,
    paramsContainer: ParamsContainer,
) : Model(), FeeSelectorModelCallback, SendNotificationsComponent.ModelCallback {

    private val params: SendWithSwapConfirmComponent.Params = paramsContainer.require()

    val uiState: StateFlow<SendWithSwapUM>
        field = MutableStateFlow(params.sendWithSwapUM)

    val primaryCurrencyStatus: CryptoCurrencyStatus = params.primaryCryptoCurrencyStatusFlow.value
    val primaryFeePaidCurrencyStatus: CryptoCurrencyStatus = params.primaryFeePaidCurrencyStatusFlow.value

    private val swapTransactionSender = swapTransactionSenderFactory.create(params.userWallet)

    private var isAmountSubtractAvailable = false

    private val amountUM
        get() = uiState.value.amountUM as? SwapAmountUM.Content
    private val destinationUM
        get() = uiState.value.destinationUM as? DestinationUM.Content
    private val feeSelectorUM
        get() = uiState.value.feeSelectorUM as? FeeSelectorUM.Content
    private val feeUMV2
        get() = uiState.value.feeSelectorUM as? FeeSelectorUMRedesigned.Content

    private val secondaryCurrencyStatus: CryptoCurrencyStatus? = amountUM?.secondaryCryptoCurrencyStatus
    val secondaryCurrency: CryptoCurrency = requireNotNull(amountUM?.secondaryCryptoCurrencyStatus?.currency) {
        "Crypto currency must not be null"
    }

    val confirmData: ConfirmData
        get() {
            val amountUM = amountUM
            val fromAmount = amountUM?.swapDirection?.withSwapDirection(
                onDirect = { amountUM.primaryAmount },
                onReverse = { amountUM.secondaryAmount },
            )
            val toAmount = amountUM?.swapDirection?.withSwapDirection(
                onDirect = { amountUM.secondaryAmount },
                onReverse = { amountUM.primaryAmount },
            )
            val amountStateFrom = fromAmount?.amountField as? AmountState.Data
            val amountStateTo = toAmount?.amountField as? AmountState.Data
            val isQuoteContent = amountUM?.selectedQuote is SwapQuoteUM.Content
            return ConfirmData(
                enteredToAmount = amountStateTo?.amountTextField?.cryptoAmount?.value,
                enteredFromAmount = amountStateFrom?.amountTextField?.cryptoAmount?.value,
                reduceAmountBy = amountStateFrom?.reduceAmountBy.takeIf { isQuoteContent }.orZero(),
                isIgnoreReduce = amountStateFrom?.isIgnoreReduce == true,
                enteredDestination = destinationUM?.addressTextField?.actualAddress,
                enteredMemo = destinationUM?.memoTextField?.value,
                fee = feeSelectorUM?.selectedFeeItem?.fee.takeIf { isQuoteContent },
                feeError = (uiState.value.feeSelectorUM as? FeeSelectorUM.Error)?.error.takeIf { isQuoteContent },
                fromCryptoCurrencyStatus = amountUM?.swapDirection?.withSwapDirection(
                    onDirect = { primaryCurrencyStatus },
                    onReverse = { secondaryCurrencyStatus },
                ),
                toCryptoCurrencyStatus = amountUM?.swapDirection?.withSwapDirection(
                    onDirect = { secondaryCurrencyStatus },
                    onReverse = { primaryCurrencyStatus },
                ),
                fromAccount = params.accountFlow.value,
                quote = amountUM?.selectedQuote,
                rateType = amountUM?.swapRateType,
                amountType = amountUM?.selectedAmountType ?: SwapAmountType.From,
                priceImpact = amountUM?.priceImpact,
            )
        }

    init {
        updateAmountSubtractAvailability()
        initialState()
        subscribeOnNotificationUpdates()
        subscribeOnTapHelpUpdates()
    }

    override fun onFeeResult(feeSelectorUM: FeeSelectorUM) {
        uiState.update { it.copy(feeSelectorUM = feeSelectorUM) }
        updateAmountSubtractAvailability()
        updateConfirmNotifications()
    }

    fun onAmountResult(amountUM: SwapAmountUM) {
        uiState.update { it.copy(amountUM = amountUM) }
        updateConfirmNotifications()
    }

    fun onDestinationResult(destinationUM: DestinationUM) {
        uiState.update { it.copy(destinationUM = destinationUM) }
        updateConfirmNotifications()
    }

    fun updateState(sendWithSwapUM: SendWithSwapUM) {
        uiState.value = sendWithSwapUM
    }

    override fun onFeeReload() {
        modelScope.launch {
            feeSelectorReloadTrigger.triggerUpdate()
        }
    }

    override fun onAmountIgnore() {
        modelScope.launch {
            swapAmountReduceTrigger.triggerIgnoreReduce()
        }
    }

    override fun onAmountReduceBy(reduceBy: BigDecimal, reduceByDiff: BigDecimal) {
        modelScope.launch {
            swapAmountReduceTrigger.triggerReduceBy(
                reduceBy = AmountReduceByTransformer.ReduceByData(
                    reduceAmountBy = reduceBy,
                    reduceAmountByDiff = reduceByDiff,
                ),
            )
        }
    }

    override fun onAmountReduceTo(reduceTo: BigDecimal) {
        modelScope.launch {
            swapAmountReduceTrigger.triggerReduceTo(reduceTo = reduceTo)
        }
    }

    fun onFeeBottomSheetShown(isShown: Boolean) {
        modelScope.launch {
            swapAmountUpdateTrigger.triggerAutoUpdateEnabled(isEnabled = !isShown)
        }
    }

    fun showEditAmount() {
        analyticsEventHandler.send(
            CommonSendAnalyticEvents.ScreenReopened(
                categoryName = params.analyticsCategoryName,
                source = SendScreenSource.Amount,
            ),
        )
        router.push(SendWithSwapRoute.Amount(isEditMode = true))
    }

    fun showEditDestination() {
        analyticsEventHandler.send(
            CommonSendAnalyticEvents.ScreenReopened(
                categoryName = params.analyticsCategoryName,
                source = SendScreenSource.Address,
            ),
        )
        router.push(SendWithSwapRoute.Destination(isEditMode = true))
    }

    suspend fun loadFee(): Either<GetFeeError, TransactionFee> {
        val defaultError = GetFeeError.UnknownError.left()

        val provider = (confirmData.quote as? SwapQuoteUM.Content)?.provider ?: return defaultError
        val amountValue = confirmData.enteredFromAmount ?: return defaultError

        return when (val providerType = provider.type) {
            ExpressProviderType.CEX -> {
                estimateFeeUseCase(
                    amount = amountValue,
                    userWallet = params.userWallet,
                    cryptoCurrencyStatus = primaryCurrencyStatus,
                ).map {
                    it.patchTransactionFeeForSwap(INCREASE_GAS_LIMIT_FOR_CEX)
                }
            }
            ExpressProviderType.DEX,
            ExpressProviderType.DEX_BRIDGE,
            ExpressProviderType.ONRAMP,
            -> GetFeeError.DataError(
                cause = IllegalStateException("Provider $providerType is not supported in Send With Swap"),
            ).left()
        }
    }

    suspend fun loadFeeExtended(maybeToken: CryptoCurrencyStatus?): Either<GetFeeError, TransactionFeeExtended> {
        val defaultError = GetFeeError.UnknownError.left()
        val provider = (confirmData.quote as? SwapQuoteUM.Content)?.provider ?: return defaultError
        val amountValue = confirmData.enteredFromAmount ?: return defaultError

        return when (val providerType = provider.type) {
            ExpressProviderType.CEX -> {
                if (maybeToken != null) {
                    estimateFeeForTokenUseCase(
                        amount = amountValue,
                        userWallet = params.userWallet,
                        feeTokenCurrencyStatus = maybeToken,
                        sendingTokenCurrencyStatus = primaryCurrencyStatus,
                    )
                } else {
                    estimateFeeForGaslessTxUseCase(
                        amount = amountValue,
                        userWallet = params.userWallet,
                        sendingTokenCurrencyStatus = primaryCurrencyStatus,
                    )
                }
            }
            ExpressProviderType.DEX,
            ExpressProviderType.DEX_BRIDGE,
            ExpressProviderType.ONRAMP,
            -> GetFeeError.DataError(
                cause = IllegalStateException("Provider $providerType is not supported in Send With Swap"),
            ).left()
        }
    }

    @Suppress("LongMethod")
    private fun onSendClick() {
        val provider = confirmData.quote?.provider ?: return
        modelScope.launch {
            uiState.transformerUpdate(SendWithSwapConfirmSendingStateTransformer(true))
            val feeExtended = feeUMV2?.feeExtraInfo?.transactionFeeExtended
            modelScope.launch(dispatchers.default) { sendClickAnalytics() }
            swapTransactionSender.sendTransaction(
                feeExtended = feeExtended,
                confirmData = confirmData,
                isAmountSubtractAvailable = isAmountSubtractAvailable,
                onExpressError = { expressError ->
                    uiState.transformerUpdate(SendWithSwapConfirmSendingStateTransformer(false))
                    val fromCurrency = confirmData.fromCryptoCurrencyStatus?.currency
                    val toCurrency = confirmData.toCryptoCurrencyStatus?.currency
                    if (fromCurrency != null && toCurrency != null) {
                        analyticsEventHandler.send(
                            SendWithSwapAnalyticEvents.ErrorExpressQuote(
                                fromToken = fromCurrency,
                                toToken = toCurrency,
                                errorDescription = "code=${expressError.code}",
                            ),
                        )
                    }
                    swapAlertFactory.getGenericErrorState(
                        expressError = expressError,
                        onFailedTxEmailClick = {
                            modelScope.launch {
                                swapAlertFactory.onFailedTxEmailClick(
                                    userWallet = params.userWallet,
                                    cryptoCurrency = confirmData.fromCryptoCurrencyStatus?.currency,
                                    errorMessage = expressError.message,
                                    confirmData = confirmData,
                                )
                            }
                        },
                        popBack = {},
                    )
                },
                onSendError = { error ->
                    uiState.transformerUpdate(SendWithSwapConfirmSendingStateTransformer(false))
                    swapAlertFactory.getSendTransactionErrorState(
                        error = error,
                        onFailedTxEmailClick = { _ ->
                            modelScope.launch {
                                swapAlertFactory.onFailedTxEmailClick(
                                    userWallet = params.userWallet,
                                    cryptoCurrency = confirmData.fromCryptoCurrencyStatus?.currency,
                                    confirmData = confirmData,
                                    errorMessage = error?.toString().orEmpty(),
                                )
                            }
                        },
                        popBack = {},
                    )
                },
                onSendSuccess = { txHash, timestamp, data ->
                    val txUrl = getExplorerTransactionUrlUseCase(
                        txHash = txHash,
                        currency = primaryCurrencyStatus.currency,
                    ).getOrNull().orEmpty()
                    appScope.launch(dispatchers.default) { sendSuccessAnalytics() }
                    uiState.transformerUpdate(
                        SendWithSwapConfirmSentStateTransformer(
                            timestamp = timestamp,
                            txUrl = txUrl,
                            provider = provider,
                            swapDataModel = data,
                        ),
                    )
                    params.callback.onResult(uiState.value)
                    router.replaceAll(SendWithSwapRoute.Success)
                },
                expressOperationType = ExpressOperationType.SEND_WITH_SWAP,
            )
        }
    }

    private fun updateAmountSubtractAvailability() {
        modelScope.launch {
            val fee = feeUMV2?.feeExtraInfo?.transactionFeeExtended?.transactionFee?.normal
            val feeTokenId =
                feeUMV2?.feeExtraInfo?.transactionFeeExtended?.feeTokenId ?: primaryCurrencyStatus.currency.id
            isAmountSubtractAvailable =
                isAmountSubtractAvailableUseCase(
                    userWalletId = params.userWallet.walletId,
                    currency = primaryCurrencyStatus.currency,
                    maybeGaslessFee = fee?.let { feeTokenId to fee },
                ).getOrElse { false }
        }
    }

    private fun initialState() {
        val confirmUM = uiState.value.confirmUM

        modelScope.launch {
            val isShowTapHelp = isSendTapHelpEnabledUseCase.invokeSync().getOrElse { false }
            if (confirmUM is ConfirmUM.Empty) {
                uiState.update { state ->
                    state.copy(
                        confirmUM = SendWithSwapConfirmInitialStateTransformer(
                            isShowTapHelp = isShowTapHelp,
                        ).transform(uiState.value.confirmUM),
                    )
                }
                updateConfirmNotifications()
            }
        }
    }

    private fun subscribeOnTapHelpUpdates() {
        isSendTapHelpEnabledUseCase().getOrNull()
            ?.onEach { showTapHelp ->
                uiState.update { state ->
                    val confirmUM = state.confirmUM as? ConfirmUM.Content
                    state.copy(confirmUM = confirmUM?.copy(isShowTapHelp = showTapHelp) ?: state.confirmUM)
                }
            }?.launchIn(modelScope)
    }

    private fun updateConfirmNotifications() {
        modelScope.launch {
            val isFixedRate = amountUM?.swapRateType == ExpressRateType.Fixed
            val feeCryptoCurrencyStatus =
                feeUMV2?.feeExtraInfo?.feeCryptoCurrencyStatus ?: params.primaryFeePaidCurrencyStatusFlow.value
            sendNotificationsUpdateTrigger.triggerUpdate(
                data = NotificationData(
                    /**
                     * Null when destination is unknown at this point (e.g. CEX swap — address is only known
                     * after receiving exchange-data). For DEX / DEX_BRIDGE, the address is known upfront.
                     */
                    destinationAddress = null,
                    memo = null,
                    amountValue = confirmData.enteredFromAmount.orZero(),
                    reduceAmountBy = confirmData.reduceAmountBy,
                    isIgnoreReduce = confirmData.isIgnoreReduce,
                    fee = confirmData.fee,
                    feeError = confirmData.feeError,
                    feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
                    isReduceAmountAvailable = !isFixedRate,
                ),
            )
            swapNotificationsUpdateTrigger.triggerUpdate(
                data = SwapNotificationData(
                    expressError = (confirmData.quote as? SwapQuoteUM.Error)?.expressError,
                    fromCryptoCurrency = confirmData.fromCryptoCurrencyStatus?.currency,
                    destinationAddress = confirmData.enteredDestination.orEmpty(),
                    memo = confirmData.enteredMemo,
                    toCryptoCurrencyStatus = confirmData.toCryptoCurrencyStatus,
                    userWalletId = params.userWallet.walletId,
                    enteredFromAmount = confirmData.enteredFromAmount,
                    fromCryptoCurrencyStatus = confirmData.fromCryptoCurrencyStatus,
                    priceImpact = confirmData.priceImpact,
                    provider = confirmData.quote?.provider,
                    amountType = confirmData.amountType,
                    shouldIncludeFeeInBalanceCheck = isFixedRate && isAmountSubtractAvailable,
                    feeValue = confirmData.fee?.amount?.value,
                ),
            )
            val isHighNetworkFee = isHighNetworkFee(feeCryptoCurrencyStatus.currency)
            uiState.transformerUpdate(
                SendWithSwapConfirmationNotificationsTransformer(isHighNetworkFee = isHighNetworkFee),
            )
        }
    }

    private suspend fun isHighNetworkFee(feeCurrency: CryptoCurrency): Boolean {
        if (!swapFeatureToggles.isHighFeeWarningEnabled) return false
        val feeAmount = confirmData.fee?.amount?.value ?: return false
        return isHighNetworkFeeUseCase(feeCurrency, feeAmount)
    }

    private fun subscribeOnNotificationUpdates() {
        combine(
            flow = sendNotificationsUpdateListener.hasErrorFlow,
            flow2 = swapNotificationsUpdateListener.hasErrorFlow,
        ) { hasSendError, hasSwapError ->
            val hasError = hasSendError || hasSwapError
            uiState.update { state ->
                val feeUM = state.feeSelectorUM as? FeeSelectorUM.Content
                val isTransactionInProcess = (state.confirmUM as? ConfirmUM.Content)?.isTransactionInProcess == true
                val isHighPriceImpact = SwapAmountQuoteUtils.isHighPriceImpact(state.amountUM)
                val isPrimaryButtonEnabled = !hasError && feeUM != null && !isTransactionInProcess && !isHighPriceImpact
                state.copy(
                    confirmUM = (state.confirmUM as? ConfirmUM.Content)?.copy(
                        isPrimaryButtonEnabled = isPrimaryButtonEnabled,
                    ) ?: state.confirmUM,
                )
            }
        }.launchIn(modelScope)
    }

    private suspend fun sendSuccessAnalytics() {
        val selectedProvider = confirmData.quote?.provider ?: return
        val fromCurrency = confirmData.fromCryptoCurrencyStatus?.currency ?: return
        val toCurrency = confirmData.toCryptoCurrencyStatus?.currency ?: return
        val feeSelectorUM = uiState.value.feeSelectorUM as? FeeSelectorUM.Content ?: return
        val feeType = feeSelectorUM.toAnalyticType()
        val fromDerivationIndex = confirmData.fromAccount?.derivationIndex?.value
        val destination = destinationUM?.addressTextField?.actualAddress ?: return
        val destinationAccount = getAccountCurrencyByAddressUseCase(destination)
            .getOrNull()?.account
        val toDerivationIndex = destinationAccount?.derivationIndex?.value

        val feeToken = getSelectedFeeToken()
        val feeAssetType = if (feeToken is CryptoCurrency.Coin) {
            AnalyticsParam.FeeAssetType.Coin
        } else {
            AnalyticsParam.FeeAssetType.Token
        }
        analyticsEventHandler.send(
            SendWithSwapAnalyticEvents.TransactionScreenOpened(
                providerName = selectedProvider.name,
                feeType = feeType,
                fromToken = fromCurrency,
                toToken = toCurrency,
                feeAssetType = feeAssetType,
                fromDerivationIndex = fromDerivationIndex,
                toDerivationIndex = toDerivationIndex,
            ),
        )
        analyticsEventHandler.send(
            Basic.TransactionSent(
                sentFrom = AnalyticsParam.TxSentFrom.SendWithSwap(
                    blockchain = fromCurrency.network.name,
                    token = fromCurrency.symbol,
                    feeType = feeType,
                    feeToken = feeToken.symbol,
                    feeAssetType = feeAssetType,
                ),
                memoType = Basic.TransactionSent.MemoType.Null,
            ),
        )
    }

    private suspend fun sendClickAnalytics() {
        val selectedProvider = confirmData.quote?.provider ?: return
        val fromCurrency = confirmData.fromCryptoCurrencyStatus?.currency ?: return
        val toCurrency = confirmData.toCryptoCurrencyStatus?.currency ?: return
        val feeSelectorUM = uiState.value.feeSelectorUM as? FeeSelectorUM.Content ?: return
        val feeType = feeSelectorUM.toAnalyticType()
        val fromDerivationIndex = confirmData.fromAccount?.derivationIndex?.value
        val destination = destinationUM?.addressTextField?.actualAddress ?: return
        val destinationAccount = getAccountCurrencyByAddressUseCase(destination)
            .getOrNull()?.account
        val toDerivationIndex = destinationAccount?.derivationIndex?.value

        analyticsEventHandler.send(
            SendWithSwapAnalyticEvents.OnSendClick(
                providerName = selectedProvider.name,
                feeType = feeType,
                fromToken = fromCurrency,
                toToken = toCurrency,
                fromDerivationIndex = fromDerivationIndex,
                toDerivationIndex = toDerivationIndex,
            ),
        )
    }

    private fun getSelectedFeeToken(): CryptoCurrency {
        val feeUMV2 = uiState.value.feeSelectorUM as? FeeSelectorUMRedesigned.Content
        val feeExtended = feeUMV2?.feeExtraInfo?.transactionFeeExtended
        val isFeeInTokenCurrency = feeExtended?.transactionFee?.normal is Fee.Ethereum.TokenCurrency
        return if (isFeeInTokenCurrency) {
            feeUMV2.feeExtraInfo.feeCryptoCurrencyStatus.currency
        } else {
            primaryCurrencyStatus.currency
        }
    }

    fun primaryButtonUM(confirmUM: ConfirmUM): NavigationButton {
        val isContent = confirmUM is ConfirmUM.Content
        val isReadyToSend = isContent && !confirmUM.isTransactionInProcess
        val isHoldToConfirm = params.userWallet.isHotWallet && isContent

        return NavigationButton(
            textReference = getPrimaryButtonText(confirmUM, isHoldToConfirm),
            iconRes = walletInterationIcon(params.userWallet),
            isIconVisible = isReadyToSend && !isHoldToConfirm,
            isHapticClick = isReadyToSend,
            isHoldToConfirm = isHoldToConfirm,
            isEnabled = confirmUM.isPrimaryButtonEnabled,
            onClick = {
                when (confirmUM) {
                    is ConfirmUM.Content -> if (confirmUM.isTransactionInProcess) {
                        return@NavigationButton
                    } else {
                        onSendClick()
                    }
                    else -> return@NavigationButton
                }
            },
        )
    }

    private fun getPrimaryButtonText(confirmUM: ConfirmUM, isHoldToConfirm: Boolean): TextReference {
        return when {
            isHoldToConfirm -> resourceReference(R.string.common_send)
            confirmUM is ConfirmUM.Success -> resourceReference(R.string.common_close)
            confirmUM is ConfirmUM.Content && confirmUM.isTransactionInProcess ->
                resourceReference(R.string.send_sending)
            else -> resourceReference(R.string.common_send)
        }
    }
}