package com.tangem.features.txhistory.converter

import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.models.network.TxInfo.TransactionType
import com.tangem.features.txhistory.impl.R
import com.tangem.features.txhistory.utils.TxHistoryUiActions
import com.tangem.utils.StringsSigns
import com.tangem.utils.annotations.RemoveWithToggle
import com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.isZero
import com.tangem.utils.toBriefAddressFormat

@Deprecated("Remove with main toggle [DesignFeatureToggles.isRedesignEnabled]. Produces pre-redesign TransactionState.")
@RemoveWithToggle("APP_REDESIGN_ENABLED")
internal class TxHistoryItemToTransactionStateConverter(
    private val currency: CryptoCurrency,
    private val txHistoryUiActions: TxHistoryUiActions,
) : Converter<TxInfo, TransactionState> {
    override fun convert(value: TxInfo): TransactionState {
        return TransactionState.Content(
            txHash = value.txHash,
            amount = value.getAmount(),
            time = value.timestampInMillis.toTimeFormat(),
            status = value.status.toUiStatus(),
            direction = value.extractDirection(),
            iconRes = value.extractIcon(),
            title = value.extractTitle(),
            subtitle = value.extractSubtitle(),
            timestamp = value.timestampInMillis,
            onClick = { txHistoryUiActions.openTxInExplorer(value.txHash) },
        )
    }

    private fun TxInfo.extractIcon(): Int = if (status == TxInfo.TransactionStatus.Failed) {
        R.drawable.ic_close_24
    } else {
        when (type) {
            is TransactionType.YieldSupply.DeployContract,
            is TransactionType.Approve,
            -> R.drawable.ic_doc_24
            is TransactionType.Staking.Stake,
            is TransactionType.Staking.Vote,
            is TransactionType.Staking.Restake,
            -> R.drawable.ic_transaction_history_staking_24
            is TransactionType.Staking.ClaimRewards,
            -> R.drawable.ic_transaction_history_claim_rewards_24
            is TransactionType.Staking.Unstake,
            is TransactionType.Staking.Withdraw,
            -> R.drawable.ic_transaction_history_unstaking_24
            is TransactionType.YieldSupply.Enter -> R.drawable.ic_connect_24
            is TransactionType.YieldSupply.InitializeToken -> R.drawable.ic_gear_24
            is TransactionType.YieldSupply.ReactivateToken -> R.drawable.ic_refresh_24
            is TransactionType.YieldSupply.Exit -> R.drawable.ic_disconnect_24
            is TransactionType.Operation,
            is TransactionType.Swap,
            is TransactionType.Transfer,
            is TransactionType.UnknownOperation,
            is TransactionType.YieldSupply.Send,
            TransactionType.YieldSupply.Topup,
            TransactionType.GaslessFee,
            -> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24
        }
    }

    @Suppress("CyclomaticComplexMethod")
    private fun TxInfo.extractTitle(): TextReference = when (val type = type) {
        is TransactionType.Approve -> resourceReference(R.string.common_approval)
        is TransactionType.Operation -> stringReference(type.name)
        is TransactionType.Swap -> resourceReference(R.string.common_swap)
        is TransactionType.Transfer -> resourceReference(R.string.common_transfer)
        is TransactionType.Staking.Stake -> resourceReference(R.string.common_stake)
        is TransactionType.Staking.Unstake -> resourceReference(R.string.common_unstake)
        is TransactionType.Staking.Vote -> resourceReference(R.string.staking_vote)
        is TransactionType.Staking.ClaimRewards -> resourceReference(R.string.common_claim_rewards)
        is TransactionType.Staking.Withdraw -> resourceReference(R.string.staking_withdraw)
        is TransactionType.Staking.Restake -> resourceReference(R.string.staking_restake)
        is TransactionType.YieldSupply -> when (type) {
            is TransactionType.YieldSupply.Enter -> resourceReference(R.string.yield_module_transaction_enter)
            is TransactionType.YieldSupply.Exit -> resourceReference(R.string.yield_module_transaction_exit)
            TransactionType.YieldSupply.Topup -> resourceReference(R.string.yield_module_transaction_topup)
            is TransactionType.YieldSupply.Send -> {
                if (type.isYieldSupplyWithdraw || isOutgoing) {
                    resourceReference(R.string.yield_module_transaction_withdraw)
                } else {
                    resourceReference(R.string.common_transfer)
                }
            }
            is TransactionType.YieldSupply.DeployContract -> resourceReference(
                R.string
                    .yield_module_transaction_deploy_contract,
            )
            is TransactionType.YieldSupply.InitializeToken -> resourceReference(
                R.string
                    .yield_module_transaction_initialize,
            )
            is TransactionType.YieldSupply.ReactivateToken -> resourceReference(
                R.string
                    .yield_module_transaction_reactivate,
            )
        }
        is TransactionType.UnknownOperation -> resourceReference(R.string.transaction_history_operation)
        TransactionType.GaslessFee -> resourceReference(R.string.gasless_transaction_fee)
    }

    private fun TxInfo.extractSubtitle(): TextReference {
        return when (val type = this.type) {
            is TransactionType.YieldSupply -> if (currency is CryptoCurrency.Coin) {
                if (type is TransactionType.YieldSupply.Send) {
                    extractSubtitleByAddressType()
                } else {
                    resourceReference(
                        R.string.transaction_history_transaction_for_address,
                        wrappedList(type.address?.toBriefAddressFormat().orEmpty()),
                    )
                }
            } else {
                when (type) {
                    is TransactionType.YieldSupply.Enter -> {
                        val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) }
                        resourceReference(R.string.yield_module_transaction_enter_subtitle, wrappedList(amount))
                    }
                    TransactionType.YieldSupply.Topup -> {
                        val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) }
                        resourceReference(R.string.yield_module_transaction_topup_subtitle, wrappedList(amount))
                    }
                    is TransactionType.YieldSupply.Exit -> {
                        val amount = amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) }
                        resourceReference(R.string.yield_module_transaction_exit_subtitle, wrappedList(amount))
                    }
                    is TransactionType.YieldSupply.Send -> {
                        if (isOutgoing || !type.isYieldSupplyWithdraw) {
                            extractSubtitleByAddressType()
                        } else {
                            val amount =
                                amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) }
                            resourceReference(
                                R.string.yield_module_transaction_exit_subtitle,
                                wrappedList(amount),
                            )
                        }
                    }
                    else -> extractSubtitleByAddressType()
                }
            }
            else -> extractSubtitleByAddressType()
        }
    }

    private fun TxInfo.extractSubtitleByAddressType(): TextReference =
        when (val interactionAddress = interactionAddressType) {
            is TxInfo.InteractionAddressType.Contract -> resourceReference(
                id = R.string.transaction_history_contract_address,
                formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
            )
            is TxInfo.InteractionAddressType.Multiple -> resourceReference(
                id = if (isOutgoing) {
                    R.string.transaction_history_transaction_to_address
                } else {
                    R.string.transaction_history_transaction_from_address
                },
                formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)),
            )
            is TxInfo.InteractionAddressType.User -> resourceReference(
                id = if (isOutgoing) {
                    R.string.transaction_history_transaction_to_address
                } else {
                    R.string.transaction_history_transaction_from_address
                },
                formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
            )
            is TxInfo.InteractionAddressType.Validator -> resourceReference(
                id = R.string.transaction_history_transaction_validator,
                formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
            )
            null -> {
                TextReference.EMPTY
            }
        }

    private fun TxInfo.extractDirection() =
        if (isOutgoing) TransactionState.Content.Direction.OUTGOING else TransactionState.Content.Direction.INCOMING

    @Suppress("ComplexCondition")
    private fun TxInfo.getAmount(): String {
        when (type) {
            is TransactionType.Staking.Vote,
            TransactionType.Staking.ClaimRewards,
            TransactionType.Staking.Withdraw,
            -> return ""

            is TransactionType.YieldSupply -> {
                if (currency is CryptoCurrency.Token && type == TransactionType.YieldSupply.Send && !isOutgoing) {
                    return ""
                }
            }
            else -> Unit
        }
        val prefix = when {
            status == TxInfo.TransactionStatus.Failed -> ""
            this.amount.isZero() -> ""
            else -> if (isOutgoing) StringsSigns.MINUS else StringsSigns.PLUS
        }
        return prefix + amount.format { crypto(symbol = currency.symbol, decimals = currency.decimals) }
    }

    private fun TxInfo.TransactionStatus.toUiStatus() = when (this) {
        TxInfo.TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed
        TxInfo.TransactionStatus.Failed -> TransactionState.Content.Status.Failed
        TxInfo.TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed
    }
}