<script setup lang="ts">
/**
 * Экран входа по резервному коду 2FA (UseRecoveryCodeView).
 *
 * Источник: ТЗ §1.6 / §22.4.2 — 8 одноразовых кодов, bcrypt-хеш в user_recovery_codes,
 * после использования помечаются `used_at`.
 *
 * Открывается из TwoFactorView ссылкой «Использовать резервный код».
 *
 * Submit → useAuthStore.useRecoveryCode() → POST /api/auth/2fa/recovery-use:
 *   - На 200 → redirect /dashboard. Бэкенд вернёт `recovery_codes_remaining`,
 *     запоминаем для toast-warning'а если осталось ≤2.
 *   - На 422 → form-error «недействителен или использован».
 *   - На 429 → lockout-alert.
 */
import { extractValidationErrors } from '../../api/client';
import { useAuthStore } from '../../stores/auth';
import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';

const router = useRouter();
const auth = useAuthStore();

const code = ref('');
const errors = ref<Record<string, string[]>>({});

const canSubmit = computed(() => code.value.trim().length >= 8);

onMounted(() => {
    // Без pending-2FA состояния тут делать нечего — отправляем на /login.
    if (!auth.requires2fa && !auth.isAuthenticated) {
        router.push('/login');
    }
});

async function handleSubmit() {
    errors.value = {};
    try {
        const response = await auth.useRecoveryCode(code.value);
        // Сохраним remaining count в session/sessionStorage для UI-warning'а
        // (отдельный коммит — в SettingsView/SecurityTab).
        if (typeof window !== 'undefined' && window.sessionStorage) {
            window.sessionStorage.setItem('recovery_codes_remaining', String(response.recovery_codes_remaining));
        }
        await router.push('/dashboard');
    } catch (error: unknown) {
        const validationErrors = extractValidationErrors(error);
        if (validationErrors) {
            errors.value = validationErrors;
        } else if (auth.lockoutSeconds === null) {
            errors.value = { code: ['Произошла ошибка. Попробуйте позже.'] };
        }
        code.value = '';
    }
}
</script>

<template>
    <v-card variant="flat" :max-width="380" width="100%" color="transparent" class="recovery-card">
        <header class="recovery-header">
            <h1 class="text-h5 mb-1">Резервный код</h1>
            <p class="text-body-2 text-medium-emphasis ma-0">
                Введите один из 8 резервных кодов. После использования код будет аннулирован.
            </p>
        </header>

        <v-alert
            v-if="auth.lockoutSeconds !== null"
            type="error"
            variant="tonal"
            density="compact"
            data-testid="lockout-alert"
        >
            Слишком много попыток. Попробуйте через {{ Math.ceil(auth.lockoutSeconds / 60) }} мин.
        </v-alert>

        <!-- ym-hide-content: Вебвизор пишет действия, но не содержимое полей.
             Закрываем контейнер целиком, а не каждое поле: класс наследуется
             детьми, и новое поле окажется закрыто само собой, без правки. -->
        <v-form class="recovery-form ym-hide-content" @submit.prevent="handleSubmit">
            <v-text-field
                v-model="code"
                label="Код (XXXX-XXXX)"
                placeholder="ABCD-1234"
                autocomplete="one-time-code"
                variant="outlined"
                density="comfortable"
                required
                :error-messages="errors.code"
            />

            <v-btn
                type="submit"
                color="primary"
                block
                size="large"
                variant="flat"
                :disabled="!canSubmit"
                :loading="auth.loading"
            >
                Войти
            </v-btn>

            <v-btn :to="{ name: '2fa' }" variant="outlined" block size="large" prepend-icon="mdi-arrow-left">
                Назад к коду из приложения
            </v-btn>
        </v-form>
    </v-card>
</template>

<style scoped>
.recovery-card {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.recovery-header h1 {
    font-variation-settings: 'opsz' 26;
    letter-spacing: -0.018em;
}

.recovery-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
</style>
