package com.tt.honeyDue.ui.screens

/**
 * P6 Stream T — BiometricLockScreen state machine (platform-independent).
 *
 * Pure logic behind [BiometricLockScreen] so it can be unit-tested in
 * commonTest without a Robolectric runtime or real BiometricPrompt.
 *
 * The state machine tracks:
 *  - whether the initial auto-prompt has been triggered,
 *  - the running count of failures (for the 3-strike PIN fallback),
 *  - whether the fallback PIN UI is currently surfaced,
 *  - and the terminal "unlocked" state.
 */
class BiometricLockState(
    /** Max biometric failures before we surface the PIN fallback. */
    val maxFailures: Int = 3,
    private val onUnlock: () -> Unit,
) {
    /** Discrete UI-visible phases. */
    enum class Phase {
        /** Initial — no prompt has been requested yet. */
        IDLE,

        /** A biometric prompt has been (or is being) shown. */
        PROMPTING,

        /** PIN fallback is visible after 3-strike lockout. */
        FALLBACK_PIN,

        /** Terminal: user is authenticated; [onUnlock] has been invoked. */
        UNLOCKED,

        /** Terminal: device has no biometric hardware — bypass lock. */
        BYPASSED,
    }

    var phase: Phase = Phase.IDLE
        private set

    var failureCount: Int = 0
        private set

    /**
     * Called once on mount. Returns true iff the caller should actually
     * show the biometric prompt. Handles the NO_HARDWARE bypass branch.
     */
    fun onAppear(availability: Availability): Boolean {
        if (phase != Phase.IDLE) return false
        return when (availability) {
            Availability.NO_HARDWARE -> {
                phase = Phase.BYPASSED
                onUnlock()
                false
            }
            Availability.AVAILABLE, Availability.NOT_ENROLLED -> {
                phase = Phase.PROMPTING
                true
            }
        }
    }

    /** Caller reports the biometric prompt succeeded. */
    fun onBiometricSuccess() {
        if (phase == Phase.UNLOCKED) return
        phase = Phase.UNLOCKED
        failureCount = 0
        onUnlock()
    }

    /**
     * Caller reports a failed biometric attempt. Returns true iff the
     * fallback PIN UI should be shown (3-strike threshold crossed).
     */
    fun onBiometricFailure(): Boolean {
        if (phase == Phase.UNLOCKED) return false
        failureCount++
        return if (failureCount >= maxFailures) {
            phase = Phase.FALLBACK_PIN
            true
        } else {
            false
        }
    }

    /** User tapped "Retry" on the lock screen — show the prompt again. */
    fun onRetry(): Boolean {
        if (phase == Phase.UNLOCKED || phase == Phase.BYPASSED) return false
        if (failureCount >= maxFailures) {
            phase = Phase.FALLBACK_PIN
            return false
        }
        phase = Phase.PROMPTING
        return true
    }

    /**
     * PIN entered in fallback. Compares against [expectedPin] (a TODO —
     * see [BiometricLockScreen] for wiring to secure storage). Returns
     * true on success; resets state and invokes [onUnlock].
     */
    fun onPinEntered(pin: String, expectedPin: String): Boolean {
        if (phase != Phase.FALLBACK_PIN) return false
        if (pin != expectedPin) return false
        phase = Phase.UNLOCKED
        failureCount = 0
        onUnlock()
        return true
    }

    /**
     * Availability flag passed in from the platform manager — mirrors
     * [com.tt.honeyDue.security.BiometricManager.Availability] but lives
     * in commonMain so the state machine is platform-agnostic.
     */
    enum class Availability {
        NO_HARDWARE,
        NOT_ENROLLED,
        AVAILABLE,
    }
}
