@page "/Account/Manage/ExternalLogins"

@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Identity
@using FWLAZ_Web.Data

@inject UserManager<IdentityUser> UserManager
@inject SignInManager<IdentityUser> SignInManager
@inject IdentityUserAccessor UserAccessor
@inject IUserStore<IdentityUser> UserStore
@inject IdentityRedirectManager RedirectManager

<PageTitle>Manage your external logins</PageTitle>

<StatusMessage />
@if (currentLogins?.Count > 0)
{
    <h3>Registered Logins</h3>
    <table class="table">
        <tbody>
            @foreach (var login in currentLogins)
            {
                <tr>
                    <td>@login.ProviderDisplayName</td>
                    <td>
                        @if (showRemoveButton)
                        {
                            <form @formname="@($"remove-login-{login.LoginProvider}")" @onsubmit="OnSubmitAsync" method="post">
                                <AntiforgeryToken />
                                <div>
                                    <input type="hidden" name="@nameof(LoginProvider)" value="@login.LoginProvider" />
                                    <input type="hidden" name="@nameof(ProviderKey)" value="@login.ProviderKey" />
                                    <button type="submit" class="btn btn-primary" title="Remove this @login.ProviderDisplayName login from your account">Remove</button>
                                </div>
                            </form>
                        }
                        else
                        {
                            @: &nbsp;
                        }
                    </td>
                </tr>
            }
        </tbody>
    </table>
}
@if (otherLogins?.Count > 0)
{
    <h4>Add another service to log in.</h4>
    <hr />
    <form class="form-horizontal" action="Account/Manage/LinkExternalLogin" method="post">
        <AntiforgeryToken />
        <div>
            <p>
                @foreach (var provider in otherLogins)
                {
                    <button type="submit" class="btn btn-primary" name="Provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">
                        @provider.DisplayName
                    </button>
                }
            </p>
        </div>
    </form>
}

@code {
    public const string LinkLoginCallbackAction = "LinkLoginCallback";

    private IdentityUser user = default!;
    private IList<UserLoginInfo>? currentLogins;
    private IList<AuthenticationScheme>? otherLogins;
    private bool showRemoveButton;

    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    [SupplyParameterFromForm]
    private string? LoginProvider { get; set; }

    [SupplyParameterFromForm]
    private string? ProviderKey { get; set; }

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

    protected override async Task OnInitializedAsync()
    {
        user = await UserAccessor.GetRequiredUserAsync(HttpContext);
        currentLogins = await UserManager.GetLoginsAsync(user);
        otherLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync())
            .Where(auth => currentLogins.All(ul => auth.Name != ul.LoginProvider))
            .ToList();

        string? passwordHash = null;
        if (UserStore is IUserPasswordStore<IdentityUser> userPasswordStore)
        {
            passwordHash = await userPasswordStore.GetPasswordHashAsync(user, HttpContext.RequestAborted);
        }

        showRemoveButton = passwordHash is not null || currentLogins.Count > 1;

        if (HttpMethods.IsGet(HttpContext.Request.Method) && Action == LinkLoginCallbackAction)
        {
            await OnGetLinkLoginCallbackAsync();
        }
    }

    private async Task OnSubmitAsync()
    {
        var result = await UserManager.RemoveLoginAsync(user, LoginProvider!, ProviderKey!);
        if (!result.Succeeded)
        {
            RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not removed.", HttpContext);
        }

        await SignInManager.RefreshSignInAsync(user);
        RedirectManager.RedirectToCurrentPageWithStatus("The external login was removed.", HttpContext);
    }

    private async Task OnGetLinkLoginCallbackAsync()
    {
        var userId = await UserManager.GetUserIdAsync(user);
        var info = await SignInManager.GetExternalLoginInfoAsync(userId);
        if (info is null)
        {
            RedirectManager.RedirectToCurrentPageWithStatus("Error: Could not load external login info.", HttpContext);
        }

        var result = await UserManager.AddLoginAsync(user, info);
        if (!result.Succeeded)
        {
            RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not added. External logins can only be associated with one account.", HttpContext);
        }

        // Clear the existing external cookie to ensure a clean login process
        await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

        RedirectManager.RedirectToCurrentPageWithStatus("The external login was added.", HttpContext);
    }
}
