@page "/Account/LoginWith2fa"

@using System.ComponentModel.DataAnnotations
@using System.Globalization
@using Microsoft.AspNetCore.Identity
@using Wave.Data

@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@inject IdentityRedirectManager RedirectManager
@inject ILogger<LoginWith2fa> Logger
@inject IStringLocalizer<LoginWith2fa> Localizer

<HeadContent>
    <meta name="robots" content="noindex,nofollow">
</HeadContent>

<PageTitle>@Localizer["Title"]</PageTitle>

<StatusMessage Message="@Message" />

<BoardComponent CenterContent="true">
    <BoardCardComponent Heading="@Localizer["Title"]">
        <p class="text-justify hyphens-auto" lang="@CultureInfo.CurrentCulture">@Localizer["Message"]</p>
        <EditForm Model="Input" FormName="login-with-2fa" OnValidSubmit="OnValidSubmitAsync" method="post">
            <input type="hidden" name="ReturnUrl" value="@ReturnUrl" />
            <input type="hidden" name="RememberMe" value="@RememberMe" />
            <DataAnnotationsValidator />
            
            <InputLabelComponent LabelText="@Localizer["TwoFactorCode_Label"]" For="() => Input.TwoFactorCode">
                <InputText @bind-Value="Input.TwoFactorCode" class="input input-bordered w-full" minlength="6" maxlength="6"
                           required aria-required="true" autocomplete="off" placeholder="@Localizer["TwoFactorCode_Placeholder"]" />
            </InputLabelComponent>
            <div class="form-control">
                <label class="label cursor-pointer">
                    <span class="label-text">@Localizer["RememberMachine_Label"]</span>
                    <InputCheckbox @bind-Value="Input.RememberMachine" class="checkbox" />
                </label>
            </div>

            <button type="submit" class="btn btn-primary w-full">@Localizer["Submit"]</button>
        </EditForm>
        <p class="mt-3">
            <a href="Account/LoginWithRecoveryCode?ReturnUrl=@ReturnUrl" class="link">
                @Localizer["RecoveryCodes_Label"]
            </a>
        </p>
    </BoardCardComponent>
</BoardComponent>


@code {
    [SupplyParameterFromQuery]
    private bool RememberMe { get; set; }
    [SupplyParameterFromForm]
    private InputModel Input { get; set; } = new();
    [SupplyParameterFromQuery]
    private string? ReturnUrl { get; set; }

    private string? Message { get; set; }
    private ApplicationUser User { get; set; } = default!;

    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() {
        string authenticatorCode = Input.TwoFactorCode!.Replace(" ", string.Empty).Replace("-", string.Empty);
        var result = await SignInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, RememberMe, Input.RememberMachine);
        string userId = await UserManager.GetUserIdAsync(User);

        if (result.Succeeded) {
            Logger.LogInformation("User with ID '{UserId}' logged in with 2fa.", userId);
            RedirectManager.RedirectTo(ReturnUrl);
        } else if (result.IsLockedOut) {
            Logger.LogWarning("User with ID '{UserId}' account locked out.", userId);
            RedirectManager.RedirectTo("Account/Lockout");
        } else {
            Logger.LogWarning("Invalid authenticator code entered for user with ID '{UserId}'.", userId);
            Message = Localizer["TwoFactorCode_ErrorInvalidCode"];
        }
    }

    private sealed class InputModel {
        [Required]
        [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Text)]
        [Display(Name = "Authenticator code")]
        public string? TwoFactorCode { get; set; }

        [Display(Name = "Remember this machine")]
        public bool RememberMachine { get; set; }
    }
}
