package com.tangem.feature.tokendetails

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.childSlot
import com.arkivanov.decompose.router.slot.dismiss
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.child
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.res.LocalRedesignEnabled
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.tokens.model.details.NavigationAction
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsModel
import com.tangem.feature.tokendetails.presentation.tokendetails.route.TokenDetailsBottomSheetConfig
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreenLegacy
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.ChooseAddressBottomSheetComponent
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.CloreMigrationBottomSheetComponent
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.DynamicAddressesBottomSheetComponent
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.bottomsheet.TransferBottomSheetComponent
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
import com.tangem.features.rating.RatingComponent
import com.tangem.features.tokendetails.ExpressTransactionsComponent
import com.tangem.features.tokendetails.TokenDetailsComponent
import com.tangem.features.tokenreceive.TokenReceiveComponent
import com.tangem.features.txhistory.component.TxHistoryComponent
import com.tangem.features.txhistory.component.TxHistoryDetailsComponent
import com.tangem.features.txhistory.component.TxHistoryDetailsSlotConfig
import com.tangem.features.yield.supply.api.YieldSupplyComponent
import com.tangem.features.yield.supply.api.YieldSupplyDepositedWarningComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject

@Suppress("LongParameterList")
internal class DefaultTokenDetailsComponent @AssistedInject constructor(
    @Assisted appComponentContext: AppComponentContext,
    @Assisted params: TokenDetailsComponent.Params,
    tokenMarketBlockComponentFactory: TokenMarketBlockComponent.Factory,
    txHistoryComponentFactory: TxHistoryComponent.Factory,
    private val txHistoryDetailsComponentFactory: TxHistoryDetailsComponent.Factory,
    expressTransactionsComponentFactory: ExpressTransactionsComponent.Factory,
    private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
    private val yieldSupplyWarningComponentFactory: YieldSupplyDepositedWarningComponent.Factory,
    private val manageFundsComponentFactory: ManageFundsComponent.Factory,
    yieldSupplyComponentFactory: YieldSupplyComponent.Factory,
    private val ratingComponentFactory: RatingComponent.Factory,
) : TokenDetailsComponent, AppComponentContext by appComponentContext {

    private val model: TokenDetailsModel = getOrCreateModel(params)
    private val txHistoryComponent = txHistoryComponentFactory.create(
        context = child("txHistoryComponent"),
        params = TxHistoryComponent.Params(
            userWalletId = params.userWalletId,
            currency = params.currency,
            openExplorer = model::onExploreClick,
            onTxDetailsRequested = { txHistoryInfo ->
                model.txDetailsNavigation.activate(TxHistoryDetailsSlotConfig(txHistoryInfo))
            },
        ),
    )

    private val expressTransactionsComponent = expressTransactionsComponentFactory.create(
        context = child("expressTransactionsComponent"),
        params = ExpressTransactionsComponent.Params(
            userWalletId = params.userWalletId,
            currency = params.currency,
            onRatingRequested = model::activateRatingForExpressTx,
            onRatingDismiss = { model.ratingSlotNavigation.dismiss() },
        ),
    )

    private val bottomSheetSlot = childSlot(
        source = model.bottomSheetNavigation,
        serializer = TokenDetailsBottomSheetConfig.serializer(),
        handleBackButton = false,
        childFactory = ::bottomSheetChild,
    )

    private val ratingSlot = childSlot(
        key = RATING_SLOT_KEY,
        source = model.ratingSlotNavigation,
        serializer = null,
        childFactory = { params, ctx ->
            ratingComponentFactory.create(childByContext(ctx), params)
        },
    )

    private val txHistoryDetailsSlot = childSlot(
        key = TX_HISTORY_DETAILS_SLOT_KEY,
        source = model.txDetailsNavigation,
        serializer = null,
        handleBackButton = true,
        childFactory = { config, ctx ->
            txHistoryDetailsComponentFactory.create(
                context = childByContext(ctx),
                params = TxHistoryDetailsComponent.Params(
                    txHistoryInfo = config.txHistoryInfo,
                    userWalletId = params.userWalletId,
                    currency = params.currency,
                    onDismiss = model.txDetailsNavigation::dismiss,
                    onOpenTokenDetails = { currency ->
                        model.txDetailsNavigation.dismiss()
                        model.openTokenDetails(currency)
                    },
                ),
            )
        },
    )

    private val tokenMarketBlockComponent = params.currency.toTokenMarketParam()
        ?.takeIf { params.shouldShowMarketBlock }
        ?.let { tokenMarketParams ->
            tokenMarketBlockComponentFactory.create(
                appComponentContext = child("tokenMarketBlockComponent"),
                params = tokenMarketParams,
            )
        }

    private val yieldSupplyComponent = yieldSupplyComponentFactory.create(
        context = child("tokenYieldSupplyComponent"),
        params = YieldSupplyComponent.Params(
            userWalletId = params.userWalletId,
            cryptoCurrency = params.currency,
            shouldHandleNavigation = (params.navigationAction as? NavigationAction.YieldSupply)
                ?.isActive,
        ),
    )

    @Composable
    override fun Content(modifier: Modifier) {
        val bottomSheet by bottomSheetSlot.subscribeAsState()
        val ratingSlotState by ratingSlot.subscribeAsState()
        val txHistoryDetails by txHistoryDetailsSlot.subscribeAsState()
        NavigationBar3ButtonsScrim()

        if (LocalRedesignEnabled.current) {
            val tokenDetailsUM by model.redesignUiState.collectAsStateWithLifecycle()

            TokenDetailsScreen(
                tokenDetailsUM = tokenDetailsUM,
                tokenMarketBlockComponent = tokenMarketBlockComponent,
                yieldSupplyComponent = yieldSupplyComponent,
                txHistoryComponent = txHistoryComponent,
                expressTransactionsComponent = expressTransactionsComponent,
                ratingComponent = ratingSlotState.child?.instance,
                modifier = modifier,
            )
        } else {
            val state by model.uiState.collectAsStateWithLifecycle()
            TokenDetailsScreenLegacy(
                state = state,
                tokenMarketBlockComponent = tokenMarketBlockComponent,
                txHistoryComponent = txHistoryComponent,
                yieldSupplyComponent = yieldSupplyComponent,
                expressTransactionsComponent = expressTransactionsComponent,
                ratingComponent = ratingSlotState.child?.instance,
            )
        }

        bottomSheet.child?.instance?.BottomSheet()
        txHistoryDetails.child?.instance?.BottomSheet()
    }

    private fun CryptoCurrency.toTokenMarketParam(): TokenMarketBlockComponent.Params? {
        id.rawCurrencyId ?: return null // token price is not available

        return TokenMarketBlockComponent.Params(cryptoCurrency = this)
    }

    private fun bottomSheetChild(
        route: TokenDetailsBottomSheetConfig,
        componentContext: ComponentContext,
    ): ComposableBottomSheetComponent = when (route) {
        is TokenDetailsBottomSheetConfig.Receive -> tokenReceiveComponentFactory.create(
            context = childByContext(componentContext),
            params = TokenReceiveComponent.Params(
                config = route.tokenReceiveConfig,
                onDismiss = model.bottomSheetNavigation::dismiss,
            ),
        )
        is TokenDetailsBottomSheetConfig.YieldSupplyWarning -> yieldSupplyWarningComponentFactory.create(
            context = childByContext(componentContext),
            params = YieldSupplyDepositedWarningComponent.Params(
                cryptoCurrency = route.cryptoCurrency,
                onDismiss = model.bottomSheetNavigation::dismiss,
                modelCallback = model,
                tokenAction = route.tokenAction,
            ),
        )
        is TokenDetailsBottomSheetConfig.ChooseAddress -> ChooseAddressBottomSheetComponent(
            currency = route.currency,
            networkAddress = route.networkAddress,
            onAddressSelected = model::onAddressTypeSelected,
            onDismiss = model.bottomSheetNavigation::dismiss,
        )
        is TokenDetailsBottomSheetConfig.CloreMigration -> CloreMigrationBottomSheetComponent(
            cloreMigrationModel = model.cloreMigrationModel,
            onDismiss = model.bottomSheetNavigation::dismiss,
        )
        is TokenDetailsBottomSheetConfig.DynamicAddresses -> DynamicAddressesBottomSheetComponent(
            dynamicAddressesDelegate = model.dynamicAddressesDelegate,
            onDismiss = model.bottomSheetNavigation::dismiss,
        )
        is TokenDetailsBottomSheetConfig.AddFunds -> manageFundsComponentFactory.create(
            context = childByContext(componentContext),
            params = ManageFundsComponent.Params(
                launchMode = ManageFundsComponent.LaunchMode.TokenActionsOnly(
                    userWalletId = route.userWalletId,
                    currency = route.currency,
                ),
                onDismiss = model.bottomSheetNavigation::dismiss,
            ),
        )
        is TokenDetailsBottomSheetConfig.Transfer -> TransferBottomSheetComponent(
            stateFlow = model.transferUiState,
            onDismiss = model.bottomSheetNavigation::dismiss,
        )
    }

    @AssistedFactory
    interface Factory : TokenDetailsComponent.Factory {
        override fun create(
            context: AppComponentContext,
            params: TokenDetailsComponent.Params,
        ): DefaultTokenDetailsComponent
    }

    companion object {
        private const val RATING_SLOT_KEY = "ratingSlot"
        private const val TX_HISTORY_DETAILS_SLOT_KEY = "txHistoryDetailsSlot"
    }
}