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.childSlot
import com.arkivanov.decompose.router.slot.dismiss
import com.arkivanov.essenty.lifecycle.subscribe
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.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.features.markets.token.block.TokenMarketBlockComponent
import com.tangem.features.tokendetails.TokenDetailsComponent
import com.tangem.features.tokenreceive.TokenReceiveComponent
import com.tangem.features.txhistory.component.TxHistoryComponent
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 tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
    private val yieldSupplyWarningComponentFactory: YieldSupplyDepositedWarningComponent.Factory,
    yieldSupplyComponentFactory: YieldSupplyComponent.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,
        ),
    )

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

    init {
        lifecycle.subscribe(
            onPause = model::onPause,
            onResume = model::onResume,
        )
    }

    private val tokenMarketBlockComponent = params.currency.toTokenMarketParam()?.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,
            handleNavigation = (params.navigationAction as? NavigationAction.YieldSupply)
                ?.isActive,
        ),
    )

    @Composable
    override fun Content(modifier: Modifier) {
        val state by model.uiState.collectAsStateWithLifecycle()
        val bottomSheet by bottomSheetSlot.subscribeAsState()
        NavigationBar3ButtonsScrim()
        TokenDetailsScreen(
            state = state,
            tokenMarketBlockComponent = tokenMarketBlockComponent,
            txHistoryComponent = txHistoryComponent,
            yieldSupplyComponent = yieldSupplyComponent,
        )
        bottomSheet.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,
            ),
        )
    }

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