@page "/Email/Subscribe"
@page "/Email/Confirm"

@using Microsoft.Extensions.Options
@using Wave.Data
@using System.ComponentModel.DataAnnotations
@using Microsoft.EntityFrameworkCore
@using Wave.Services
@using Wave.Utilities	

@inject ILogger<EmailSignup> Logger
@inject IStringLocalizer<EmailSignup> Localizer
@inject IDbContextFactory<ApplicationDbContext> ContextFactory
@inject IOptions<Features> Features
@inject IEmailService EmailService
@inject EmailFactory Email
@inject IMessageDisplay Messages
@inject NavigationManager Navigation

<HeadContent>
	<meta name="robots" content="nofollow">
	<link rel="canonical" href="@(new UriBuilder(Navigation.BaseUri) { Scheme = "https", Port = -1, Path = "/email/subscribe" }.Uri.AbsoluteUri)" />
</HeadContent>

<PageTitle>@(Localizer["Title"] + TitlePostfix)</PageTitle>

<BoardComponent CenterContent="true">
	<BoardCardComponent Heading="@Localizer["Title"]">
		<EditForm method="post" FormName="email-signup" Model="Model" OnValidSubmit="OnValidSubmit">
			<DataAnnotationsValidator />

			<InputLabelComponent LabelText="@Localizer["Name_Label"]" For="() => Model.Name">
				<InputText @bind-Value="Model.Name" class="input input-bordered w-full" autocomplete="name"
				           placeholder="@Localizer["Name_Placeholder"]" />
			</InputLabelComponent>
			<InputLabelComponent LabelText="@Localizer["Email_Label"]" For="() => Model.Name">
				<InputText @bind-Value="Model.Email" class="input input-bordered w-full" autocomplete="email" type="email"
						   required aria-required="true" placeholder="@Localizer["Email_Placeholder"]" />
			</InputLabelComponent>

			<button type="submit" class="btn btn-primary w-full">@Localizer["Submit"]</button>
		</EditForm>
	</BoardCardComponent>
</BoardComponent>

@code {
	[CascadingParameter(Name = "TitlePostfix")]
	private string TitlePostfix { get; set; } = default!;
	[SupplyParameterFromForm(FormName = "email-signup")]
	private InputModel Model { get; set; } = new();

	[Parameter, SupplyParameterFromQuery(Name = "user")]
	public string? Id { get; set; }
	[Parameter, SupplyParameterFromQuery(Name = "token")]
    public string? Token { get; set; }

	protected override async Task OnInitializedAsync() {
		if (Features.Value.EmailSubscriptions is not true)
			throw new ApplicationException("Email subscriptions not enabled.");

		if (Id is null || Token is null) return;
		try {
			var id = await Email.IsTokenValid(Id, Token);

			if (id is null) {
				Messages.ShowError(Localizer["Failure_Message"]);
				return;
			}

			await using var context = await ContextFactory.CreateDbContextAsync();
			var subscriber = context.Set<EmailSubscriber>().IgnoreQueryFilters().FirstOrDefault(s => s.Id == id);
			if (subscriber is null) {
				Messages.ShowError(Localizer["Failure_Message"]);
				return;
			}
			subscriber.Unsubscribed = false;
			await context.SaveChangesAsync();
			Messages.ShowSuccess(Localizer["Success_Message"]);

			await Email.ClearToken(Id, Token);

			var articles = await context.Set<EmailNewsletter>()
				.IgnoreAutoIncludes().IgnoreQueryFilters().Where(n => n.IsSend)
				.Include(a => a.Article).ThenInclude(a => a.Author)
				.OrderByDescending(a => a.DistributionDateTime)
				.Take(3)
				.ToListAsync();
			var mail = await Email.CreateWelcomeEmail(
				subscriber, articles,
				Localizer["WelcomeEmailSubject"], 
				Localizer["WelcomeEmailTitle"], 
				Localizer["WelcomeEmailBody"],
				Localizer["WelcomeEmailBody"]);

			await EmailService.ConnectAsync(CancellationToken.None);
			await EmailService.SendEmailAsync(mail);
			await EmailService.DisconnectAsync(CancellationToken.None);
		} catch (Exception ex) {
			Logger.LogError(ex, "Error trying to confirm subscriber.");
			Messages.ShowError(Localizer["Failure_Message"]);
		}
	}

	private async Task OnValidSubmit() {
		if (Features.Value.EmailSubscriptions is not true)
			throw new ApplicationException("Email subscriptions not enabled.");

		try {
			Messages.ShowSuccess(Localizer["Submit_Message"]);
			await using var context = await ContextFactory.CreateDbContextAsync();

			var subscriber = context.Set<EmailSubscriber>().IgnoreQueryFilters().FirstOrDefault(s => s.Email == Model.Email);
			if (subscriber?.Unsubscribed is false) return;

			subscriber ??= new EmailSubscriber {
				Email = Model.Email.Trim(),
				Unsubscribed = true, 
				Language = "en-US" // TODO
			};
			subscriber.Name = Model.Name;
			subscriber.UnsubscribeReason = "Not Confirmed";
			context.Update(subscriber);
			await context.SaveChangesAsync();

			if (subscriber.Unsubscribed) {
				var email = await Email.CreateConfirmationEmail(subscriber,
					Localizer["ConfirmEmailSubject"],
					Localizer["ConfirmEmailTitle"],
					Localizer["ConfirmEmailBody"],
					Localizer["ConfirmEmailBody"],
					Localizer["Submit"]);

				await EmailService.ConnectAsync(CancellationToken.None);
				await EmailService.SendEmailAsync(email);
				await EmailService.DisconnectAsync(CancellationToken.None);
			}

			Model = new();
		} catch (Exception ex) {
			Logger.LogError(ex, "Failed to create subscriber/send confirmation mail.");
		}
	}

	private sealed class InputModel {
		[MaxLength(128)]
		public string? Name { get; set; }
		[EmailAddress, Required(AllowEmptyStrings = false), MaxLength(256)]
		public string Email { get; set; } = string.Empty;
	}
}
