@page "/Account/Manage/ExternalLogins"

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

@inject UserManager<ApplicationUser> UserManager
@inject SignInManager<ApplicationUser> SignInManager
@inject IdentityUserAccessor UserAccessor
@inject IUserStore<ApplicationUser> UserStore
@inject IdentityRedirectManager RedirectManager
@inject IStringLocalizer<ExternalLogin> Localizer

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

<StatusMessage/>

@if (CurrentLogins?.Count > 0) {
	<BoardComponent>
		<BoardCardComponent Heading="@Localizer["Title"]">
			<div class="overflow-x-auto">
				<table class="table">
					<thead>
					<tr>
						<th>Provider</th>
						<th></th>
					</tr>
					</thead>
					<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>
			</div>
		</BoardCardComponent>
		@if (OtherLogins?.Count > 0) {
			<BoardCardComponent Heading="Add another service to log in.">
				<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>
			</BoardCardComponent>
		}
	</BoardComponent>
}

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

	private ApplicationUser User { get; set; } = default!;
	private IList<UserLoginInfo>? CurrentLogins { get; set; }
	private IList<AuthenticationScheme>? OtherLogins { get; set; }
	private bool ShowRemoveButton { get; set; }

	[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<ApplicationUser> 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);
	}

}