@page "/Account/LoginWithRecoveryCode"

@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Identity
@using MyAppName.WebApp.Components.Account
@using OpenArchival.DataAccess

@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@inject IdentityRedirectManager RedirectManager
@inject ILogger<LoginWithRecoveryCode> Logger

<PageTitle>Recovery code verification</PageTitle>

<h1>Recovery code verification</h1>
<hr />
<StatusMessage Message="@message" />
<p>
    You have requested to log in with a recovery code. This login will not be remembered until you provide
    an authenticator app code at log in or disable 2FA and log in again.
</p>
<div class="row">
    <div class="col-md-4">
        <EditForm Model="Input" FormName="login-with-recovery-code" OnValidSubmit="OnValidSubmitAsync" method="post">
            <DataAnnotationsValidator />
            <ValidationSummary class="text-danger" role="alert" />
            <div class="form-floating mb-3">
                <InputText @bind-Value="Input.RecoveryCode" id="Input.RecoveryCode" class="form-control" autocomplete="off" placeholder="RecoveryCode" />
                <label for="Input.RecoveryCode" class="form-label">Recovery Code</label>
                <ValidationMessage For="() => Input.RecoveryCode" class="text-danger" />
            </div>
            <button type="submit" class="w-100 btn btn-lg btn-primary">Log in</button>
        </EditForm>
    </div>
</div>

@code {
    private string? message;
    private ApplicationUser user = default!;

    [SupplyParameterFromForm]
    private InputModel Input { get; set; } = new();

    [SupplyParameterFromQuery]
    private string? ReturnUrl { get; set; }

    protected override async Task OnInitializedAsync()
    {
        // Ensure the user has gone through the username & password screen first
        user = await SignInManager.GetTwoFactorAuthenticationUserAsync() ??
            throw new InvalidOperationException("Unable to load two-factor authentication user.");
    }

    private async Task OnValidSubmitAsync()
    {
        var recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty);

        var result = await SignInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode);

        var userId = await UserManager.GetUserIdAsync(user);

        if (result.Succeeded)
        {
            Logger.LogInformation("User with ID '{UserId}' logged in with a recovery code.", userId);
            RedirectManager.RedirectTo(ReturnUrl);
        }
        else if (result.IsLockedOut)
        {
            Logger.LogWarning("User account locked out.");
            RedirectManager.RedirectTo("Account/Lockout");
        }
        else
        {
            Logger.LogWarning("Invalid recovery code entered for user with ID '{UserId}' ", userId);
            message = "Error: Invalid recovery code entered.";
        }
    }

    private sealed class InputModel
    {
        [Required]
        [DataType(DataType.Text)]
        [Display(Name = "Recovery Code")]
        public string RecoveryCode { get; set; } = "";
    }
}
