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

import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.router.stack.pop
import com.arkivanov.decompose.value.ObserveLifecycleMode
import com.arkivanov.decompose.value.subscribe
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableModularContentComponent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.swap.models.R
import com.tangem.domain.swap.models.SwapDirection
import com.tangem.features.send.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.api.subcomponents.destination.DestinationRoute
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponent
import com.tangem.features.send.api.subcomponents.destination.SendDestinationComponentParams
import com.tangem.features.swap.v2.api.SendWithSwapComponent
import com.tangem.features.swap.v2.impl.amount.SwapAmountComponent
import com.tangem.features.swap.v2.impl.amount.SwapAmountComponentParams
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
import com.tangem.features.swap.v2.impl.common.SwapUtils.SEND_WITH_SWAP_PROVIDER_TYPES
import com.tangem.features.swap.v2.impl.common.entity.ConfirmUM
import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticEvents
import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticEvents.NoticeFixedRate.toAnalyticsRateType
import com.tangem.features.swap.v2.impl.sendviaswap.confirm.SendWithSwapConfirmComponent
import com.tangem.features.swap.v2.impl.sendviaswap.model.SendWithSwapModel
import com.tangem.features.swap.v2.impl.sendviaswap.success.SendWithSwapSuccessComponent
import com.tangem.features.swap.v2.impl.sendviaswap.ui.SendWithSwapContent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.launch

internal class DefaultSendWithSwapComponent @AssistedInject constructor(
    @Assisted private val appComponentContext: AppComponentContext,
    @Assisted private val params: SendWithSwapComponent.Params,
    private val sendDestinationComponentFactory: SendDestinationComponent.Factory,
    private val confirmComponentFactory: SendWithSwapConfirmComponent.Factory,
    private val analyticsEventHandler: AnalyticsEventHandler,
) : SendWithSwapComponent, AppComponentContext by appComponentContext {

    private val stackNavigation = StackNavigation<SendWithSwapRoute>()

    private val innerRouter = InnerRouter<SendWithSwapRoute>(
        stackNavigation = stackNavigation,
        popCallback = { onChildBack() },
    )

    private val model: SendWithSwapModel = getOrCreateModel(params = params, router = innerRouter)

    private val childStack = childStack(
        key = "sendWithSwapInnerStack",
        source = stackNavigation,
        serializer = null,
        initialConfiguration = model.initialRoute,
        handleBackButton = true,
        childFactory = { configuration, componentContext ->
            createChild(
                route = configuration,
                childContext = childByContext(
                    componentContext = componentContext,
                    router = innerRouter,
                ),
            )
        },
    )

    init {
        childStack.subscribe(
            lifecycle = lifecycle,
            mode = ObserveLifecycleMode.CREATE_DESTROY,
        ) { stack ->
            componentScope.launch {
                when (val activeComponent = stack.active.instance) {
                    is SwapAmountComponent -> {
                        activeComponent.updateState(model.uiState.value.amountUM)
                    }
                    is SendDestinationComponent -> {
                        analyticsEventHandler.send(
                            CommonSendAnalyticEvents.AddressScreenOpened(
                                categoryName = model.analyticCategoryName,
                                source = model.analyticsSendSource,
                            ),
                        )
                        activeComponent.updateState(model.uiState.value.destinationUM)
                    }
                    is SendWithSwapConfirmComponent -> {
                        if (stack.active.configuration.isEditMode) {
                            activeComponent.updateState(model.uiState.value)
                        }
                        // Re-sync destination from parent on Confirm entry, bypassing the edit-mode gate ([REDACTED_TASK_KEY]).
                        activeComponent.updateDestinationState(model.uiState.value.destinationUM)
                        val fromCurrency = params.currency
                        val content = model.uiState.value.amountUM as? SwapAmountUM.Content ?: return@launch
                        val toCurrency = content.secondaryCryptoCurrencyStatus?.currency ?: return@launch
                        val rateType = content.swapRateType.toAnalyticsRateType()
                        val providerName = content.selectedQuote.provider?.name.orEmpty()

                        analyticsEventHandler.send(
                            SendWithSwapAnalyticEvents.ConfirmationScreenOpened(
                                providerName = providerName,
                                rateType = rateType,
                                fromToken = fromCurrency,
                                toToken = toCurrency,
                            ),
                        )
                    }
                }
            }
        }
    }

    @Composable
    override fun Content(modifier: Modifier) {
        val stackState by childStack.subscribeAsState()

        BackHandler(
            onBack = ::onChildBack,
        )

        SendWithSwapContent(
            stackState = stackState,
        )
    }

    private fun createChild(route: SendWithSwapRoute, childContext: AppComponentContext) = when (route) {
        is SendWithSwapRoute.Amount -> getAmountComponent(route, factoryContext = childContext)
        is SendWithSwapRoute.Destination -> getDestinationComponent(route = route, factoryContext = childContext)
        is SendWithSwapRoute.Confirm -> getConfirmComponent(factoryContext = childContext)
        is SendWithSwapRoute.Success -> getSuccessComponent(factoryContext = childContext)
    }

    private fun getAmountComponent(
        route: SendWithSwapRoute.Amount,
        factoryContext: AppComponentContext,
    ): ComposableModularContentComponent {
        return SwapAmountComponent(
            appComponentContext = factoryContext,
            params = SwapAmountComponentParams.AmountParams(
                amountUM = model.uiState.value.amountUM,
                title = resourceReference(R.string.common_send),
                route = route,
                isBalanceHidingFlow = model.isBalanceHiddenFlow,
                analyticsCategoryName = model.analyticCategoryName,
                primaryCryptoCurrencyStatusFlow = model.primaryCryptoCurrencyStatusFlow,
                secondaryCryptoCurrency = null,
                swapDirection = SwapDirection.Direct,
                callback = model,
                userWallet = model.userWallet,
                filterProviderTypes = SEND_WITH_SWAP_PROVIDER_TYPES,
                analyticsSendSource = model.analyticsSendSource,
                accountFlow = model.accountFlow,
                isAccountModeFlow = model.isAccountModeFlow,
            ),
        )
    }

    private fun getDestinationComponent(
        route: DestinationRoute,
        factoryContext: AppComponentContext,
    ): ComposableModularContentComponent {
        val amountContentUM = model.uiState.value.amountUM as? SwapAmountUM.Content
            ?: return ComposableModularContentComponent.EMPTY
        val secondaryCryptoCurrency = amountContentUM.secondaryCryptoCurrencyStatus?.currency
            ?: return ComposableModularContentComponent.EMPTY

        return sendDestinationComponentFactory.create(
            context = factoryContext,
            params = SendDestinationComponentParams.DestinationParams(
                state = model.uiState.value.destinationUM,
                route = route,
                isBalanceHidingFlow = model.isBalanceHiddenFlow,
                analyticsCategoryName = model.analyticCategoryName,
                analyticsSendSource = model.analyticsSendSource,
                title = resourceReference(R.string.common_address),
                userWalletId = params.userWalletId,
                cryptoCurrency = secondaryCryptoCurrency,
                callback = model,
                isAllowSelfSend = true,
            ),
        )
    }

    private fun getConfirmComponent(factoryContext: AppComponentContext): ComposableModularContentComponent {
        return confirmComponentFactory.create(
            appComponentContext = factoryContext,
            params = SendWithSwapConfirmComponent.Params(
                sendWithSwapUM = model.uiState.value,
                isBalanceHidingFlow = model.isBalanceHiddenFlow,
                appCurrency = model.appCurrency,
                userWallet = model.userWallet,
                callback = model,
                analyticsCategoryName = model.analyticCategoryName,
                primaryCryptoCurrencyStatusFlow = model.primaryCryptoCurrencyStatusFlow,
                primaryFeePaidCurrencyStatusFlow = model.primaryFeePaidCurrencyStatusFlow,
                accountFlow = model.accountFlow,
                isAccountModeFlow = model.isAccountModeFlow,
                analyticsSendSource = model.analyticsSendSource,
                swapDirection = SwapDirection.Direct,
            ),
        )
    }

    private fun getSuccessComponent(factoryContext: AppComponentContext): ComposableModularContentComponent {
        return SendWithSwapSuccessComponent(
            appComponentContext = factoryContext,
            params = SendWithSwapSuccessComponent.Params(
                sendWithSwapUMFlow = model.uiState,
                callback = model,
                analyticsCategoryName = model.analyticCategoryName,
            ),
        )
    }

    private fun onChildBack() {
        val isEmptyStack = childStack.value.backStack.isEmpty()
        val isSuccess = model.uiState.value.confirmUM is ConfirmUM.Success
        val isSendingInProgress = (model.uiState.value.confirmUM as? ConfirmUM.Content)?.isTransactionInProcess == true

        val isPopSend = isEmptyStack || isSuccess

        when {
            isSendingInProgress -> Unit // Do not anything while transaction sending in progress
            isPopSend -> router.pop()
            else -> stackNavigation.pop()
        }
    }

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