/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.bouncer.domain.interactor

import android.hardware.biometrics.BiometricSourceType
import android.os.CountDownTimer
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.bouncer.shared.model.Message
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES
import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.res.R.string.bouncer_face_not_recognized
import com.android.systemui.res.R.string.keyguard_enter_password
import com.android.systemui.res.R.string.keyguard_enter_pattern
import com.android.systemui.res.R.string.keyguard_enter_pin
import com.android.systemui.res.R.string.kg_bio_too_many_attempts_password
import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pattern
import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pin
import com.android.systemui.res.R.string.kg_bio_try_again_or_password
import com.android.systemui.res.R.string.kg_bio_try_again_or_pattern
import com.android.systemui.res.R.string.kg_bio_try_again_or_pin
import com.android.systemui.res.R.string.kg_face_locked_out
import com.android.systemui.res.R.string.kg_fp_not_recognized
import com.android.systemui.res.R.string.kg_primary_auth_locked_out_password
import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pattern
import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pin
import com.android.systemui.res.R.string.kg_prompt_after_dpm_lock
import com.android.systemui.res.R.string.kg_prompt_after_update_password
import com.android.systemui.res.R.string.kg_prompt_after_update_pattern
import com.android.systemui.res.R.string.kg_prompt_after_update_pin
import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_password
import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pattern
import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pin
import com.android.systemui.res.R.string.kg_prompt_auth_timeout
import com.android.systemui.res.R.string.kg_prompt_password_auth_timeout
import com.android.systemui.res.R.string.kg_prompt_pattern_auth_timeout
import com.android.systemui.res.R.string.kg_prompt_pin_auth_timeout
import com.android.systemui.res.R.string.kg_prompt_reason_restart_password
import com.android.systemui.res.R.string.kg_prompt_reason_restart_pattern
import com.android.systemui.res.R.string.kg_prompt_reason_restart_pin
import com.android.systemui.res.R.string.kg_prompt_unattended_update
import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
import com.android.systemui.res.R.string.kg_trust_agent_disabled
import com.android.systemui.res.R.string.kg_unlock_with_password_or_fp
import com.android.systemui.res.R.string.kg_unlock_with_pattern_or_fp
import com.android.systemui.res.R.string.kg_unlock_with_pin_or_fp
import com.android.systemui.res.R.string.kg_wrong_input_try_fp_suggestion
import com.android.systemui.res.R.string.kg_wrong_password_try_again
import com.android.systemui.res.R.string.kg_wrong_pattern_try_again
import com.android.systemui.res.R.string.kg_wrong_pin_try_again
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.Quint
import javax.inject.Inject
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn

private const val SYS_BOOT_REASON_PROP = "sys.boot.reason.last"
private const val REBOOT_MAINLINE_UPDATE = "reboot,mainline_update"
private const val TAG = "BouncerMessageInteractor"

@SysUISingleton
class BouncerMessageInteractor
@Inject
constructor(
    private val repository: BouncerMessageRepository,
    private val userRepository: UserRepository,
    private val countDownTimerUtil: CountDownTimerUtil,
    private val featureFlags: FeatureFlags,
    private val updateMonitor: KeyguardUpdateMonitor,
    trustRepository: TrustRepository,
    biometricSettingsRepository: BiometricSettingsRepository,
    private val systemPropertiesHelper: SystemPropertiesHelper,
    primaryBouncerInteractor: PrimaryBouncerInteractor,
    @Application private val applicationScope: CoroutineScope,
    private val facePropertyRepository: FacePropertyRepository,
    deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
    faceAuthRepository: DeviceEntryFaceAuthRepository,
    private val securityModel: KeyguardSecurityModel,
) {

    private val isFingerprintAuthCurrentlyAllowed =
        deviceEntryFingerprintAuthRepository.isLockedOut
            .isFalse()
            .and(biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed)
            .stateIn(applicationScope, SharingStarted.Eagerly, false)

    private val currentSecurityMode
        get() = securityModel.getSecurityMode(currentUserId)
    private val currentUserId
        get() = userRepository.getSelectedUserInfo().id

    private val kumCallback =
        object : KeyguardUpdateMonitorCallback() {
            override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
                repository.setMessage(
                    when (biometricSourceType) {
                        BiometricSourceType.FINGERPRINT ->
                            incorrectFingerprintInput(currentSecurityMode)
                        BiometricSourceType.FACE ->
                            incorrectFaceInput(
                                currentSecurityMode,
                                isFingerprintAuthCurrentlyAllowed.value
                            )
                        else ->
                            defaultMessage(
                                currentSecurityMode,
                                isFingerprintAuthCurrentlyAllowed.value
                            )
                    }
                )
            }

            override fun onBiometricAcquired(
                biometricSourceType: BiometricSourceType?,
                acquireInfo: Int
            ) {
                super.onBiometricAcquired(biometricSourceType, acquireInfo)
            }

            override fun onBiometricAuthenticated(
                userId: Int,
                biometricSourceType: BiometricSourceType?,
                isStrongBiometric: Boolean
            ) {
                repository.setMessage(defaultMessage)
            }
        }

    private val isAnyBiometricsEnabledAndEnrolled =
        biometricSettingsRepository.isFaceAuthEnrolledAndEnabled.or(
            biometricSettingsRepository.isFingerprintEnrolledAndEnabled
        )

    private val wasRebootedForMainlineUpdate
        get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE

    private val isFaceAuthClass3
        get() = facePropertyRepository.sensorInfo.value?.strength == SensorStrength.STRONG

    private val initialBouncerMessage: Flow<BouncerMessageModel> =
        combine(
                biometricSettingsRepository.authenticationFlags,
                trustRepository.isCurrentUserTrustManaged,
                isAnyBiometricsEnabledAndEnrolled,
                deviceEntryFingerprintAuthRepository.isLockedOut,
                faceAuthRepository.isLockedOut,
                ::Quint
            )
            .map { (flags, _, biometricsEnrolledAndEnabled, fpLockedOut, faceLockedOut) ->
                val isTrustUsuallyManaged = trustRepository.isCurrentUserTrustUsuallyManaged.value
                val trustOrBiometricsAvailable =
                    (isTrustUsuallyManaged || biometricsEnrolledAndEnabled)
                return@map if (
                    trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterReboot
                ) {
                    if (wasRebootedForMainlineUpdate) {
                        authRequiredForMainlineUpdate(currentSecurityMode)
                    } else {
                        authRequiredAfterReboot(currentSecurityMode)
                    }
                } else if (trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterTimeout) {
                    authRequiredAfterPrimaryAuthTimeout(currentSecurityMode)
                } else if (flags.isPrimaryAuthRequiredAfterDpmLockdown) {
                    authRequiredAfterAdminLockdown(currentSecurityMode)
                } else if (
                    trustOrBiometricsAvailable && flags.primaryAuthRequiredForUnattendedUpdate
                ) {
                    authRequiredForUnattendedUpdate(currentSecurityMode)
                } else if (fpLockedOut) {
                    class3AuthLockedOut(currentSecurityMode)
                } else if (faceLockedOut) {
                    if (isFaceAuthClass3) {
                        class3AuthLockedOut(currentSecurityMode)
                    } else {
                        faceLockedOut(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
                    }
                } else if (
                    trustOrBiometricsAvailable &&
                        flags.strongerAuthRequiredAfterNonStrongBiometricsTimeout
                ) {
                    nonStrongAuthTimeout(
                        currentSecurityMode,
                        isFingerprintAuthCurrentlyAllowed.value
                    )
                } else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterUserRequest) {
                    trustAgentDisabled(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
                } else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterTrustAgentExpired) {
                    trustAgentDisabled(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
                } else if (trustOrBiometricsAvailable && flags.isInUserLockdown) {
                    authRequiredAfterUserLockdown(currentSecurityMode)
                } else {
                    defaultMessage
                }
            }

    fun onPrimaryAuthLockedOut(secondsBeforeLockoutReset: Long) {
        if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return

        val callback =
            object : CountDownTimerCallback {
                override fun onFinish() {
                    repository.setMessage(defaultMessage)
                }

                override fun onTick(millisUntilFinished: Long) {
                    val secondsRemaining = (millisUntilFinished / 1000.0).roundToInt()
                    val message = primaryAuthLockedOut(currentSecurityMode)
                    message.message?.animate = false
                    message.message?.formatterArgs =
                        mutableMapOf<String, Any>(Pair("count", secondsRemaining))
                    repository.setMessage(message)
                }
            }
        countDownTimerUtil.startNewTimer(secondsBeforeLockoutReset * 1000, 1000, callback)
    }

    fun onPrimaryAuthIncorrectAttempt() {
        if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return

        repository.setMessage(
            incorrectSecurityInput(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
        )
    }

    fun setFingerprintAcquisitionMessage(value: String?) {
        if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
        repository.setMessage(
            defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
        )
    }

    fun setFaceAcquisitionMessage(value: String?) {
        if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
        repository.setMessage(
            defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
        )
    }

    fun setCustomMessage(value: String?) {
        if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return

        repository.setMessage(
            defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
        )
    }

    private val defaultMessage: BouncerMessageModel
        get() = defaultMessage(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)

    fun onPrimaryBouncerUserInput() {
        if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
        repository.setMessage(defaultMessage)
    }

    val bouncerMessage = repository.bouncerMessage

    init {
        updateMonitor.registerCallback(kumCallback)

        combine(primaryBouncerInteractor.isShowing, initialBouncerMessage) { showing, bouncerMessage
                ->
                if (showing) {
                    bouncerMessage
                } else {
                    null
                }
            }
            .filterNotNull()
            .onEach { repository.setMessage(it) }
            .launchIn(applicationScope)
    }
}

interface CountDownTimerCallback {
    fun onFinish()
    fun onTick(millisUntilFinished: Long)
}

@SysUISingleton
open class CountDownTimerUtil @Inject constructor() {

    /**
     * Start a new count down timer that runs for [millisInFuture] with a tick every
     * [millisInterval]
     */
    fun startNewTimer(
        millisInFuture: Long,
        millisInterval: Long,
        callback: CountDownTimerCallback,
    ): CountDownTimer {
        return object : CountDownTimer(millisInFuture, millisInterval) {
                override fun onFinish() = callback.onFinish()

                override fun onTick(millisUntilFinished: Long) =
                    callback.onTick(millisUntilFinished)
            }
            .start()
    }
}

private fun Flow<Boolean>.or(anotherFlow: Flow<Boolean>) =
    this.combine(anotherFlow) { a, b -> a || b }

private fun Flow<Boolean>.and(anotherFlow: Flow<Boolean>) =
    this.combine(anotherFlow) { a, b -> a && b }

private fun Flow<Boolean>.isFalse() = this.map { !it }

private fun defaultMessage(
    securityMode: SecurityMode,
    secondaryMessage: String?,
    fpAuthIsAllowed: Boolean
): BouncerMessageModel {
    return BouncerMessageModel(
        message =
            Message(
                messageResId = defaultMessage(securityMode, fpAuthIsAllowed).message?.messageResId,
                animate = false
            ),
        secondaryMessage = Message(message = secondaryMessage, animate = false)
    )
}

private fun defaultMessage(
    securityMode: SecurityMode,
    fpAuthIsAllowed: Boolean
): BouncerMessageModel {
    return if (fpAuthIsAllowed) {
        defaultMessageWithFingerprint(securityMode)
    } else
        when (securityMode) {
            SecurityMode.Pattern -> Pair(keyguard_enter_pattern, 0)
            SecurityMode.Password -> Pair(keyguard_enter_password, 0)
            SecurityMode.PIN -> Pair(keyguard_enter_pin, 0)
            else -> Pair(0, 0)
        }.toMessage()
}

private fun defaultMessageWithFingerprint(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, 0)
        SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, 0)
        SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, 0)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun incorrectSecurityInput(
    securityMode: SecurityMode,
    fpAuthIsAllowed: Boolean
): BouncerMessageModel {
    return if (fpAuthIsAllowed) {
        incorrectSecurityInputWithFingerprint(securityMode)
    } else
        when (securityMode) {
            SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, 0)
            SecurityMode.Password -> Pair(kg_wrong_password_try_again, 0)
            SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, 0)
            else -> Pair(0, 0)
        }.toMessage()
}

private fun incorrectSecurityInputWithFingerprint(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, kg_wrong_input_try_fp_suggestion)
        SecurityMode.Password -> Pair(kg_wrong_password_try_again, kg_wrong_input_try_fp_suggestion)
        SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, kg_wrong_input_try_fp_suggestion)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun incorrectFingerprintInput(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pattern)
        SecurityMode.Password -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_password)
        SecurityMode.PIN -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pin)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun incorrectFaceInput(
    securityMode: SecurityMode,
    fpAuthIsAllowed: Boolean
): BouncerMessageModel {
    return if (fpAuthIsAllowed) incorrectFaceInputWithFingerprintAllowed(securityMode)
    else
        when (securityMode) {
            SecurityMode.Pattern -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pattern)
            SecurityMode.Password -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_password)
            SecurityMode.PIN -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pin)
            else -> Pair(0, 0)
        }.toMessage()
}

private fun incorrectFaceInputWithFingerprintAllowed(
    securityMode: SecurityMode
): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, bouncer_face_not_recognized)
        SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, bouncer_face_not_recognized)
        SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, bouncer_face_not_recognized)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun biometricLockout(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_bio_too_many_attempts_pattern)
        SecurityMode.Password -> Pair(keyguard_enter_password, kg_bio_too_many_attempts_password)
        SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_bio_too_many_attempts_pin)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun authRequiredAfterReboot(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_reason_restart_pattern)
        SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_reason_restart_password)
        SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun authRequiredAfterAdminLockdown(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_dpm_lock)
        SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_dpm_lock)
        SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun authRequiredAfterUserLockdown(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_user_lockdown_pattern)
        SecurityMode.Password ->
            Pair(keyguard_enter_password, kg_prompt_after_user_lockdown_password)
        SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun authRequiredForUnattendedUpdate(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_unattended_update)
        SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_unattended_update)
        SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_unattended_update)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun authRequiredForMainlineUpdate(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_update_pattern)
        SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_update_password)
        SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_update_pin)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun authRequiredAfterPrimaryAuthTimeout(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout)
        SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_password_auth_timeout)
        SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun nonStrongAuthTimeout(
    securityMode: SecurityMode,
    fpAuthIsAllowed: Boolean
): BouncerMessageModel {
    return if (fpAuthIsAllowed) {
        nonStrongAuthTimeoutWithFingerprintAllowed(securityMode)
    } else
        when (securityMode) {
            SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_auth_timeout)
            SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_auth_timeout)
            SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_auth_timeout)
            else -> Pair(0, 0)
        }.toMessage()
}

fun nonStrongAuthTimeoutWithFingerprintAllowed(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_prompt_auth_timeout)
        SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_prompt_auth_timeout)
        SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_prompt_auth_timeout)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun faceLockedOut(
    securityMode: SecurityMode,
    fpAuthIsAllowed: Boolean
): BouncerMessageModel {
    return if (fpAuthIsAllowed) faceLockedOutButFingerprintAvailable(securityMode)
    else
        when (securityMode) {
            SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out)
            SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out)
            SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_face_locked_out)
            else -> Pair(0, 0)
        }.toMessage()
}

private fun faceLockedOutButFingerprintAvailable(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_face_locked_out)
        SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_face_locked_out)
        SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_face_locked_out)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun class3AuthLockedOut(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_bio_too_many_attempts_pattern)
        SecurityMode.Password -> Pair(keyguard_enter_password, kg_bio_too_many_attempts_password)
        SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_bio_too_many_attempts_pin)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun trustAgentDisabled(
    securityMode: SecurityMode,
    fpAuthIsAllowed: Boolean
): BouncerMessageModel {
    return if (fpAuthIsAllowed) trustAgentDisabledWithFingerprintAllowed(securityMode)
    else
        when (securityMode) {
            SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_trust_agent_disabled)
            SecurityMode.Password -> Pair(keyguard_enter_password, kg_trust_agent_disabled)
            SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_trust_agent_disabled)
            else -> Pair(0, 0)
        }.toMessage()
}

private fun trustAgentDisabledWithFingerprintAllowed(
    securityMode: SecurityMode
): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_trust_agent_disabled)
        SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_trust_agent_disabled)
        SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_trust_agent_disabled)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun primaryAuthLockedOut(securityMode: SecurityMode): BouncerMessageModel {
    return when (securityMode) {
        SecurityMode.Pattern ->
            Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pattern)
        SecurityMode.Password ->
            Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_password)
        SecurityMode.PIN ->
            Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pin)
        else -> Pair(0, 0)
    }.toMessage()
}

private fun Pair<Int, Int>.toMessage(): BouncerMessageModel {
    return BouncerMessageModel(
        message = Message(messageResId = this.first, animate = false),
        secondaryMessage = Message(messageResId = this.second, animate = false)
    )
}
