package com.tangem.feature.wallet.child.wallet

import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.decompose.ExperimentalDecomposeApi
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.doOnResume
import com.tangem.common.routing.AppRoute
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.DesignFeatureToggles
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
import com.tangem.core.ui.components.haze.hazeEffectTangem
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.decompose.ComposableDialogComponent
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.tokens.model.details.TokenAction
import com.tangem.feature.wallet.child.managetokens.AddAndManageBottomSheetComponent
import com.tangem.feature.wallet.child.organizetokens.OrganizeTokensComponent
import com.tangem.feature.wallet.child.tokenActions.DefaultTokenActionsComponent
import com.tangem.feature.wallet.child.tokenActions.TokenActionsComponent
import com.tangem.feature.wallet.child.wallet.model.WalletModel
import com.tangem.feature.wallet.navigation.WalletRoute
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig
import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen
import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen2
import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.KycRejectedComponent
import com.tangem.feature.walletsettings.component.RenameWalletComponent
import com.tangem.features.biometry.AskBiometryComponent
import com.tangem.features.commonfeatures.api.managefunds.ManageFundsComponent
import com.tangem.features.commonfeatures.api.portfolioselector.PortfolioSelectorComponent
import com.tangem.features.feed.entry.components.FeedEntryComponent
import com.tangem.features.promobanners.api.PromoBannersBlockComponent
import com.tangem.features.pushnotifications.api.PushNotificationsBottomSheetComponent
import com.tangem.features.pushnotifications.api.PushNotificationsParams
import com.tangem.features.send.api.NetworkSelectionComponent
import com.tangem.features.tangempay.component.TangemPayMainBlockComponent
import com.tangem.features.tangempay.components.TangemPayTransactionBottomSheetComponent
import com.tangem.features.tokenreceive.TokenReceiveComponent
import com.tangem.features.virtualaccount.main.component.VirtualAccountMainBlockComponent
import com.tangem.features.yield.supply.api.YieldSupplyDepositedWarningComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.launch

@OptIn(ExperimentalDecomposeApi::class)
@Suppress("LongParameterList")
internal class WalletComponent @AssistedInject constructor(
    @Assisted appComponentContext: AppComponentContext,
    @Assisted navigate: (WalletRoute) -> Unit,
    feedEntryComponentFactory: FeedEntryComponent.Factory,
    tangemPayMainBlockComponentFactory: TangemPayMainBlockComponent.Factory,
    virtualAccountMainBlockComponentFactory: VirtualAccountMainBlockComponent.Factory,
    private val tangemPayTransactionBottomSheetComponentFactory: TangemPayTransactionBottomSheetComponent.Factory,
    private val renameWalletComponentFactory: RenameWalletComponent.Factory,
    private val askBiometryComponentFactory: AskBiometryComponent.Factory,
    private val pushNotificationsBottomSheetComponent: PushNotificationsBottomSheetComponent.Factory,
    private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
    private val yieldSupplyDepositedWarningComponent: YieldSupplyDepositedWarningComponent.Factory,
    private val promoBannersBlockComponentFactory: PromoBannersBlockComponent.Factory,
    private val networkSelectionComponentFactory: NetworkSelectionComponent.Factory,
    private val tokenActionsComponentFactory: TokenActionsComponent.Factory,
    private val portfolioSelectorComponentFactory: PortfolioSelectorComponent.Factory,
    private val manageFundsComponentFactory: ManageFundsComponent.Factory,
    private val designFeatureToggles: DesignFeatureToggles,
) : ComposableContentComponent, AppComponentContext by appComponentContext {

    private val model: WalletModel = getOrCreateModel()

    private val feedEntryComponent by lazy {
        feedEntryComponentFactory.create(
            context = child("feedEntryComponent"),
            entryRoute = null,
        )
    }
    private val tangemPayMainBlockComponent by lazy {
        tangemPayMainBlockComponentFactory.create(
            context = child("tangemPayMainBlockComponent"),
            params = Unit,
        )
    }
    private val virtualAccountMainBlockComponent by lazy {
        virtualAccountMainBlockComponentFactory.create(
            context = child("virtualAccountMainBlockComponent"),
            params = Unit,
        )
    }

    private val promoBannersBlockComponent: PromoBannersBlockComponent by lazy {
        promoBannersBlockComponentFactory.create(
            context = child("promoBannersBlockComponent"),
            params = PromoBannersBlockComponent.Params(
                placeholder = PromoBannersBlockComponent.Placeholder.MAIN,
            ),
        )
    }

    init {
        lifecycle.subscribe(model.screenLifecycleProvider)
        doOnResume { model.onResume() }
        componentScope.launch { model.innerWalletRouter.navigateToFlow.collect { navigate(it) } }
    }

    private val dialog = childSlot(
        source = model.innerWalletRouter.dialogNavigation,
        serializer = WalletDialogConfig.serializer(),
        handleBackButton = true,
        childFactory = { dialogConfig, componentContext ->
            when (dialogConfig) {
                is WalletDialogConfig.RenameWallet -> {
                    renameWalletComponentFactory.create(
                        context = childByContext(componentContext),
                        params = RenameWalletComponent.Params(
                            userWalletId = dialogConfig.userWalletId,
                            currentName = dialogConfig.currentName,
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                        ),
                    )
                }
                is WalletDialogConfig.AskForBiometry -> {
                    askBiometryComponentFactory.create(
                        context = childByContext(componentContext),
                        params = AskBiometryComponent.Params(
                            isBottomSheetVariant = true,
                            modelCallbacks = model.askBiometryModelCallbacks,
                        ),
                    )
                }
                WalletDialogConfig.AskForPushNotifications -> pushNotificationsBottomSheetComponent.create(
                    context = childByContext(componentContext),
                    params = PushNotificationsParams(
                        isBottomSheet = true,
                        modelCallbacks = model.askForPushNotificationsModelCallbacks,
                        source = AppRoute.PushNotification.Source.Main,
                    ),
                )
                is WalletDialogConfig.TokenReceive -> {
                    tokenReceiveComponentFactory.create(
                        context = childByContext(componentContext),
                        params = TokenReceiveComponent.Params(
                            config = dialogConfig.tokenReceiveConfig,
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                        ),
                    )
                }
                is WalletDialogConfig.YieldSupplyWarning -> {
                    yieldSupplyDepositedWarningComponent.create(
                        context = childByContext(componentContext),
                        params = YieldSupplyDepositedWarningComponent.Params(
                            cryptoCurrency = dialogConfig.cryptoCurrency,
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                            tokenAction = dialogConfig.tokenAction,
                            modelCallback = object : YieldSupplyDepositedWarningComponent.ModelCallback {
                                override fun onYieldSupplyWarningAcknowledged(tokenAction: TokenAction) {
                                    dialogConfig.onWarningAcknowledged(tokenAction)
                                }
                            },
                        ),
                    )
                }
                is WalletDialogConfig.KycRejected -> {
                    KycRejectedComponent(
                        appComponentContext = childByContext(componentContext),
                        params = KycRejectedComponent.Params(
                            walletId = dialogConfig.walletId,
                            customerId = dialogConfig.customerId,
                            callbacks = model.tangemPayKycRejectedCallbacks,
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                        ),
                    )
                }
                is WalletDialogConfig.TokenActionList -> {
                    tokenActionsComponentFactory.create(
                        context = childByContext(componentContext),
                        params = TokenActionsComponent.Params(
                            actions = dialogConfig.actionList,
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                            tokenRowUM = dialogConfig.tokenRowUM,
                            offsetX = dialogConfig.offsetX,
                            offsetY = dialogConfig.offsetY,
                        ),
                    )
                }
                is WalletDialogConfig.AddFunds -> {
                    manageFundsComponentFactory.create(
                        context = childByContext(componentContext),
                        params = ManageFundsComponent.Params(
                            launchMode = ManageFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                        ),
                    )
                }
                is WalletDialogConfig.Transfer -> {
                    manageFundsComponentFactory.create(
                        context = childByContext(componentContext),
                        params = ManageFundsComponent.Params(
                            launchMode = ManageFundsComponent.LaunchMode.ChooseToken(dialogConfig.userWalletId),
                            flowType = ManageFundsComponent.FlowType.Transfer,
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                        ),
                    )
                }
                is WalletDialogConfig.AddAndManage -> {
                    AddAndManageBottomSheetComponent(
                        appComponentContext = childByContext(componentContext),
                        params = AddAndManageBottomSheetComponent.Params(
                            userWalletId = dialogConfig.userWalletId,
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                            onOrganizeTokensClick = {
                                model.innerWalletRouter.openOrganizeTokensScreen(dialogConfig.userWalletId)
                            },
                            onManageTokensClick = { accountId ->
                                model.innerWalletRouter.openManageTokensScreen(
                                    accountId = accountId,
                                    source = AppRoute.ManageTokens.Source.WALLET,
                                )
                            },
                        ),
                        portfolioSelectorComponentFactory = portfolioSelectorComponentFactory,
                    )
                }
                is WalletDialogConfig.OrganizeTokens -> {
                    OrganizeTokensComponent(
                        appComponentContext = childByContext(componentContext),
                        params = OrganizeTokensComponent.Params(
                            userWalletId = dialogConfig.userWalletId,
                            callback = model.innerWalletRouter.organizeCallbacks,
                        ),
                    )
                }
                is WalletDialogConfig.NetworkSelection -> {
                    networkSelectionComponentFactory.create(
                        context = childByContext(componentContext),
                        params = NetworkSelectionComponent.Params(
                            address = dialogConfig.address,
                            amount = dialogConfig.amount,
                            memo = dialogConfig.memo,
                            walletGroups = dialogConfig.walletGroups.map { walletGroup ->
                                NetworkSelectionComponent.Params.WalletGroup(
                                    userWalletId = walletGroup.userWalletId,
                                    walletName = walletGroup.walletName,
                                    accounts = walletGroup.accounts.map { accountGroup ->
                                        NetworkSelectionComponent.Params.AccountGroup(
                                            accountId = accountGroup.accountId,
                                            accountName = accountGroup.accountName,
                                            currencies = accountGroup.currencies,
                                            hiddenTokensCount = accountGroup.hiddenTokensCount,
                                        )
                                    },
                                )
                            },
                            onTokenSelected = { userWalletId, currency ->
                                model.innerWalletRouter.dialogNavigation.dismiss()
                                model.innerWalletRouter.openSend(
                                    userWalletId = userWalletId,
                                    currency = currency,
                                    address = dialogConfig.address,
                                    amount = dialogConfig.amount?.parseBigDecimal(currency.decimals),
                                    tag = dialogConfig.memo,
                                    entryType = AppRoute.Send.EntryType.Manual,
                                )
                            },
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                        ),
                    )
                }
                is WalletDialogConfig.TangemPayTransactionDetails -> {
                    tangemPayTransactionBottomSheetComponentFactory.create(
                        context = childByContext(componentContext),
                        params = TangemPayTransactionBottomSheetComponent.Params(
                            isBalanceHidden = dialogConfig.isBalanceHidden,
                            transaction = dialogConfig.transaction,
                            userWalletId = dialogConfig.walletId,
                            customerId = dialogConfig.customerId,
                            onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
                        ),
                    )
                }
            }
        },
    )

    @Composable
    override fun Content(modifier: Modifier) {
        val bottomSheetState = remember { mutableStateOf(BottomSheetState.COLLAPSED) }
        var headerSize by remember { mutableStateOf(0.dp) }
        val dialog by dialog.subscribeAsState()
        val uiState by model.uiState.collectAsStateWithLifecycle()
        if (designFeatureToggles.isRedesignEnabled) {
            WalletScreen2(
                state = uiState,
                promoBannersBlockComponent = promoBannersBlockComponent,
                tangemPayComponent = tangemPayMainBlockComponent,
                virtualAccountComponent = virtualAccountMainBlockComponent,
                bottomSheetContent = { onExpandSheet ->
                    BottomSheetContent(
                        bottomSheetState = bottomSheetState,
                        onHeaderSizeChange = { headerSize = it },
                        onExpandSheet = onExpandSheet,
                        modifier = modifier,
                    )
                },
                bottomSheetHeaderHeightProvider = { headerSize },
                onBottomSheetStateChange = { bottomSheetState.value = it },
            )
        } else {
            WalletScreen(
                state = uiState,
                promoBannersBlockComponent = promoBannersBlockComponent,
                tangemPayComponent = tangemPayMainBlockComponent,
                virtualAccountComponent = virtualAccountMainBlockComponent,
                bottomSheetContent = { onExpandSheet ->
                    BottomSheetContent(
                        bottomSheetState = bottomSheetState,
                        onHeaderSizeChange = { headerSize = it },
                        onExpandSheet = onExpandSheet,
                        modifier = modifier,
                    )
                },
                bottomSheetHeaderHeightProvider = { headerSize },
                onBottomSheetStateChange = { bottomSheetState.value = it },
            )
        }

        when (val dialog = dialog.child?.instance) {
            is ComposableDialogComponent -> dialog.Dialog()
            is DefaultTokenActionsComponent -> {
                if (designFeatureToggles.isRedesignEnabled) {
                    dialog.Content(Modifier.hazeEffectTangem())
                } else {
                    dialog.BottomSheet()
                }
            }
            is ComposableBottomSheetComponent -> dialog.BottomSheet()
            else -> {}
        }
    }

    @Composable
    private fun BottomSheetContent(
        bottomSheetState: State<BottomSheetState>,
        onHeaderSizeChange: (Dp) -> Unit,
        onExpandSheet: () -> Unit,
        modifier: Modifier = Modifier,
    ) {
        feedEntryComponent.BottomSheetContent(
            bottomSheetState = bottomSheetState,
            onHeaderSizeChange = onHeaderSizeChange,
            onExpandSheet = onExpandSheet,
            modifier = modifier,
        )
    }

    @AssistedFactory
    interface Factory {
        fun create(appComponentContext: AppComponentContext, navigate: (WalletRoute) -> Unit): WalletComponent
    }
}