package com.tangem.features.hotwallet.walletactivation.entry

import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.pop
import com.arkivanov.decompose.router.stack.push
import com.arkivanov.decompose.router.stack.replaceAll
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.utils.TrackingContextProxy
import com.tangem.core.decompose.di.GlobalUiMessageSender
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.R
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.settings.ShouldAskPermissionUseCase
import com.tangem.domain.hotwallet.SetAccessCodeSkippedUseCase
import com.tangem.domain.wallets.analytics.WalletSettingsAnalyticEvents
import com.tangem.features.hotwallet.manualbackup.check.ManualBackupCheckComponent
import com.tangem.features.hotwallet.manualbackup.completed.ManualBackupCompletedComponent
import com.tangem.features.hotwallet.manualbackup.phrase.ManualBackupPhraseComponent
import com.tangem.features.hotwallet.manualbackup.start.ManualBackupStartComponent
import com.tangem.features.hotwallet.accesscode.AccessCodeComponent
import com.tangem.features.hotwallet.setupfinished.MobileWalletSetupFinishedComponent
import com.tangem.features.hotwallet.walletactivation.entry.routing.WalletActivationRoute
import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION
import com.tangem.features.hotwallet.WalletActivationComponent
import com.tangem.features.hotwallet.stepper.api.HotWalletStepperComponent
import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@Suppress("LongParameterList")
@ModelScoped
internal class WalletActivationModel @Inject constructor(
    paramsContainer: ParamsContainer,
    override val dispatchers: CoroutineDispatcherProvider,
    private val router: Router,
    private val shouldAskPermissionUseCase: ShouldAskPermissionUseCase,
    private val setAccessCodeSkippedUseCase: SetAccessCodeSkippedUseCase,
    @GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
    private val trackingContextProxy: TrackingContextProxy,
    private val analyticsEventHandler: AnalyticsEventHandler,
) : Model() {

    val params = paramsContainer.require<WalletActivationComponent.Params>()

    val hotWalletStepperComponentModelCallback = HotWalletStepperComponentModelCallback()
    val manualBackupStartModelCallbacks = ManualBackupStartModelCallbacks()
    val manualBackupPhraseModelCallbacks = ManualBackupPhraseModelCallbacks()
    val manualBackupCheckModelCallbacks = ManualBackupCheckModelCallbacks()
    val manualBackupCompletedModelCallbacks = ManualBackupCompletedModelCallbacks()
    val accessCodeModelCallbacks = AccessCodeModelCallbacks()
    val pushNotificationsCallbacks = PushNotificationsCallbacks()
    val mobileWalletSetupFinishedModelCallbacks = MobileWalletSetupFinishedModelCallbacks()

    private val isStartingWithAccessCode = params.isBackupExists
    val stackNavigation = StackNavigation<WalletActivationRoute>()
    val startRoute = if (isStartingWithAccessCode) {
        WalletActivationRoute.SetAccessCode
    } else {
        WalletActivationRoute.ManualBackupStart
    }
    val currentRoute: MutableStateFlow<WalletActivationRoute> = MutableStateFlow(startRoute)

    private val analyticsSource = AnalyticsParam.ScreensSources.Main
    private val analyticsAction = WalletSettingsAnalyticEvents.RecoveryPhraseScreenAction.Backup

    init {
        trackingContextProxy.addHotWalletContext()
        when (startRoute) {
            is WalletActivationRoute.ManualBackupStart -> {
                analyticsEventHandler.send(
                    event = WalletSettingsAnalyticEvents.RecoveryPhraseScreenInfo(
                        source = analyticsSource.value,
                        action = analyticsAction.value,
                    ),
                )
            }
            is WalletActivationRoute.SetAccessCode -> {
                analyticsEventHandler.send(
                    event = WalletSettingsAnalyticEvents.AccessCodeScreenOpened(
                        source = analyticsSource.value,
                    ),
                )
            }
            else -> Unit
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        trackingContextProxy.removeContext()
    }

    fun onChildBack() {
        when (currentRoute.value) {
            is WalletActivationRoute.ManualBackupStart -> router.pop()
            is WalletActivationRoute.ManualBackupPhrase -> stackNavigation.pop()
            is WalletActivationRoute.ManualBackupCheck -> stackNavigation.pop()
            is WalletActivationRoute.ManualBackupCompleted -> Unit
            is WalletActivationRoute.SetAccessCode -> if (isStartingWithAccessCode) {
                router.pop()
            }
            is WalletActivationRoute.ConfirmAccessCode -> stackNavigation.pop()
            is WalletActivationRoute.PushNotifications -> Unit
            is WalletActivationRoute.SetupFinished -> Unit
        }
    }

    private fun navigateToPushNotificationsOrNext() {
        modelScope.launch {
            val shouldRequestPush = shouldAskPermissionUseCase(PUSH_PERMISSION)
            if (shouldRequestPush) {
                stackNavigation.replaceAll(WalletActivationRoute.PushNotifications)
            } else {
                stackNavigation.replaceAll(WalletActivationRoute.SetupFinished)
            }
        }
    }

    private fun navigateToSetupFinished() {
        stackNavigation.replaceAll(WalletActivationRoute.SetupFinished)
    }

    private fun showSkipAccessCodeWarningDialog() {
        val userWalletId = params.userWalletId

        uiMessageSender.send(
            DialogMessage(
                message = resourceReference(R.string.access_code_alert_skip_description),
                title = resourceReference(R.string.access_code_alert_skip_title),
                firstAction = EventMessageAction(
                    title = resourceReference(R.string.common_cancel),
                    onClick = {},
                ),
                secondAction = EventMessageAction(
                    title = resourceReference(R.string.access_code_alert_skip_ok),
                    onClick = {
                        modelScope.launch(NonCancellable) {
                            setAccessCodeSkippedUseCase(userWalletId, true)
                        }
                        navigateToPushNotificationsOrNext()
                    },
                ),
                shouldDismissOnFirstAction = true,
            ),
        )
    }

    inner class HotWalletStepperComponentModelCallback : HotWalletStepperComponent.ModelCallback {
        var canSkip = true

        override fun onBackClick() {
            onChildBack()
        }

        override fun onSkipClick() {
            if (canSkip) {
                showSkipAccessCodeWarningDialog()
            }
        }
    }

    inner class ManualBackupStartModelCallbacks : ManualBackupStartComponent.ModelCallbacks {
        override fun onContinueClick() {
            stackNavigation.push(WalletActivationRoute.ManualBackupPhrase)
            analyticsEventHandler.send(
                event = WalletSettingsAnalyticEvents.RecoveryPhraseScreen(
                    source = analyticsSource.value,
                    action = analyticsAction.value,
                ),
            )
        }
    }

    inner class ManualBackupPhraseModelCallbacks : ManualBackupPhraseComponent.ModelCallbacks {
        override fun onContinueClick() {
            stackNavigation.push(WalletActivationRoute.ManualBackupCheck)
            analyticsEventHandler.send(
                event = WalletSettingsAnalyticEvents.RecoveryPhraseCheck(
                    source = analyticsSource.value,
                    action = analyticsAction.value,
                ),
            )
        }
    }

    inner class ManualBackupCheckModelCallbacks : ManualBackupCheckComponent.ModelCallbacks {
        override fun onCompleteClick() {
            stackNavigation.push(WalletActivationRoute.ManualBackupCompleted)
            analyticsEventHandler.send(
                event = WalletSettingsAnalyticEvents.BackupCompleteScreen(
                    source = analyticsSource.value,
                    action = analyticsAction.value,
                ),
            )
        }
    }

    inner class ManualBackupCompletedModelCallbacks : ManualBackupCompletedComponent.ModelCallbacks {
        override fun onContinueClick(userWalletId: UserWalletId) {
            analyticsEventHandler.send(
                event = WalletSettingsAnalyticEvents.AccessCodeScreenOpened(source = analyticsSource.value),
            )
            stackNavigation.push(WalletActivationRoute.SetAccessCode)
        }

        override fun onUpgradeClick(userWalletId: UserWalletId) = Unit
    }

    inner class AccessCodeModelCallbacks : AccessCodeComponent.ModelCallbacks {
        override fun onNewAccessCodeInput(userWalletId: UserWalletId, accessCode: String) {
            analyticsEventHandler.send(
                event = WalletSettingsAnalyticEvents.ReEnterAccessCodeScreen(source = analyticsSource.value),
            )
            stackNavigation.push(WalletActivationRoute.ConfirmAccessCode(accessCode))
        }

        override fun onAccessCodeUpdateStarted(userWalletId: UserWalletId) {
            hotWalletStepperComponentModelCallback.canSkip = false
        }

        override fun onAccessCodeUpdated(userWalletId: UserWalletId) {
            navigateToPushNotificationsOrNext()
            hotWalletStepperComponentModelCallback.canSkip = true
        }
    }

    inner class PushNotificationsCallbacks : PushNotificationsModelCallbacks {
        override fun onAllowSystemPermission() {
            navigateToSetupFinished()
        }

        override fun onDenySystemPermission() {
            navigateToSetupFinished()
        }

        override fun onDismiss() {
            navigateToSetupFinished()
        }
    }

    inner class MobileWalletSetupFinishedModelCallbacks : MobileWalletSetupFinishedComponent.ModelCallbacks {
        override fun onFinishClick() {
            router.pop()
        }
    }
}