package com.tangem.features.biometry.impl.model

import androidx.compose.runtime.Stable
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.ui.UiMessageSender
import com.tangem.core.navigation.settings.SettingsManager
import com.tangem.core.ui.R
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.settings.SetAskBiometryShownUseCase
import com.tangem.domain.settings.repositories.SettingsRepository
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.features.biometry.AskBiometryComponent
import com.tangem.features.biometry.impl.ui.state.AskBiometryUM
import com.tangem.features.hotwallet.HotWalletFeatureToggles
import com.tangem.sdk.api.TangemSdkManager
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject

@Suppress("LongParameterList")
@Stable
@ModelScoped
internal class AskBiometryModel @Inject constructor(
    override val dispatchers: CoroutineDispatcherProvider,
    paramsContainer: ParamsContainer,
    private val setAskBiometryShownUseCase: SetAskBiometryShownUseCase,
    private val settingsRepository: SettingsRepository,
    private val tangemSdkManager: TangemSdkManager,
    private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
    private val walletsRepository: WalletsRepository,
    private val cardSdkConfigRepository: CardSdkConfigRepository,
    private val settingsManager: SettingsManager,
    private val uiMessageSender: UiMessageSender,
    private val userWalletsListRepository: UserWalletsListRepository,
    private val hotWalletFeatureToggles: HotWalletFeatureToggles,
) : Model() {

    private val params = paramsContainer.require<AskBiometryComponent.Params>()

    private val _uiState = MutableStateFlow(
        AskBiometryUM(
            bottomSheetVariant = params.isBottomSheetVariant,
            onAllowClick = ::onAllowClick,
            onDontAllowClick = ::dontAllow,
            onDismiss = ::dismiss,
        ),
    )
    val uiState = _uiState.asStateFlow()
    val dismissBSFlow = MutableSharedFlow<Unit>()

    init {
        modelScope.launch {
            setAskBiometryShownUseCase()
        }
    }

    fun dismiss() {
        modelScope.launch {
            dismissBSFlow.emit(Unit)
            delay(timeMillis = 500)
            dontAllow()
        }
    }

    private fun onAllowClick() {
        modelScope.launch {
            if (tangemSdkManager.checkNeedEnrollBiometrics()) {
                showEnrollBiometricsDialog()
                return@launch
            }

            _uiState.update { it.copy(showProgress = true) }

            /*

             * because it will be automatically saved on UserWalletsListManager switch
             */
            val selectedUserWallet = getSelectedWalletUseCase.sync().getOrNull() ?: run {
                Timber.e("Unable to save user wallet")
                uiMessageSender.send(
                    SnackbarMessage(stringReference("No selected user wallet")),
                )
                _uiState.update { it.copy(showProgress = false) }

                return@launch
            }

            handleSuccessAllowing(selectedUserWallet)
        }
    }

    private fun dontAllow() {
        params.modelCallbacks.onDenied()
    }

    private suspend fun handleSuccessAllowing(userWallet: UserWallet) {
        walletsRepository.saveShouldSaveUserWallets(item = true)

        if (hotWalletFeatureToggles.isHotWalletEnabled) {
            walletsRepository.setUseBiometricAuthentication(value = true)
            walletsRepository.setRequireAccessCode(value = false)
            setBiometryLockForAllWallets()
            cardSdkConfigRepository.setAccessCodeRequestPolicy(
                isBiometricsRequestPolicy = walletsRepository.requireAccessCode().not(),
            )
        } else {
            settingsRepository.setShouldSaveAccessCodes(value = true)
            if (userWallet is UserWallet.Cold) {
                cardSdkConfigRepository.setAccessCodeRequestPolicy(
                    isBiometricsRequestPolicy = userWallet.hasAccessCode,
                )
            }
        }

        if (_uiState.value.bottomSheetVariant) {
            dismissBSFlow.emit(Unit)
            delay(timeMillis = 500)
        }

        params.modelCallbacks.onAllowed()
    }

    private suspend fun setBiometryLockForAllWallets() {
        userWalletsListRepository.userWalletsSync().forEach { userWallet ->
            userWalletsListRepository.setLock(
                userWalletId = userWallet.walletId,
                lockMethod = UserWalletsListRepository.LockMethod.Biometric,
                changeUnsecured = false,
            ).onLeft {
                uiMessageSender.send(
                    SnackbarMessage(stringReference("Something went wrong. Please contact support: $it")),
                )
            }
        }
    }

    private fun showEnrollBiometricsDialog() {
        uiMessageSender.send(
            DialogMessage(
                message = resourceReference(R.string.save_user_wallet_agreement_enroll_biometrics_description),
                title = resourceReference(R.string.save_user_wallet_agreement_enroll_biometrics_title),
                firstAction = EventMessageAction(
                    title = resourceReference(R.string.common_enable),
                    onClick = { settingsManager.openBiometricSettings() },
                ),
                secondAction = EventMessageAction(
                    title = resourceReference(R.string.common_cancel),
                    onClick = {},
                ),
                shouldDismissOnFirstAction = true,
            ),
        )
    }
}