@inherits LocalizableComponentBase

<EditForm Model="MessageForm" OnValidSubmit="OnValidSubmit">
	<DataAnnotationsValidator />

	<div class="field mb-3">
		<div class="control">
			<InputText class="input rounded-t-[1.4rem] rounded-b-lg neoInput" maxlength="64"
								 placeholder="@Localizer["Title (optional)"]" Value="@MessageForm.Title"
								 ValueChanged="(v) => OnTitleChanged(v)"
								 ValueExpression="() => MessageForm.Title" />
		</div>
		<div class="control relative mt-1">
			<textarea @bind="@MessageForm.Content" @bind:event="oninput"
								class="textarea rounded-b-[1.4rem] rounded-t-lg neoInput"
								maxlength="5000"
								placeholder="@Localizer["oh shit... here we go again"]" rows="3"></textarea>
			<span class="absolute text-xs opacity-50 right-2 bottom-1">@(MessageForm.Content?.Length ?? 0)/5000</span>
		</div>
		@if (showPreviewButton && isPreviewOpen && MessageForm.Content is { Length: > 0 })
		{
			<div class="control relative mt-1 px-8">
				<div class="neomorphInset rounded-t-lg rounded-b-[1.4rem] px-2 py-1 md:px-3 md:py-2 text-xs md:text-sm">
					@switch (MessageForm.ContentType)
					{
						case ContentType.Markdown:
							@((MarkupString)Markdown.ToHtml(MessageForm.Content))
							break;
						case ContentType.HTML:
							<p>@((MarkupString)MessageForm.Content)</p>
							break;
					}
				</div>
			</div>
		}
		<div class="help is-danger">
			<ValidationMessage For="() => MessageForm.Content" />
			@contentError
		</div>
	</div>

	<div class="flex flex-col space-y-3 mb-3 @SUtility.IfTrueThen(MessageForm.Media.Count == 0, "hidden")">
		@foreach (var media in MessageForm.Media)
		{
			switch (MessageForm.MediaType)
			{
				case MediaType.Images:
					<div class="flex w-full items-center space-x-3 rounded-xl p-3 md:p-4 neomorph is-nxxsmall">
						<img alt="@media.AltText" class="object-cover rounded-lg neomorph is-nxxsmall max-h-24 md:max-h-40 max-w-[6rem] md:max-w-[12rem]" src="@media.Base64Preview" />
						<div class="flex w-full self-start flex-col justify-between space-y-2">
							<div class="flex w-full space-x-3">
								<div class="flex-1">
									<p class="text-xs md:text-sm break-all">
										<i class="ion-md-image"></i> <b>@media.FileName</b>
									</p>
									<p class="text-xs break-all">
										<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(Localizer._pLocalizer)
									</p>
								</div>
								<button class="button is-small is-rounded self-start neoBtnSmall" @onclick="() => RemoveFile(media)" type="button">
									<span class="icon">
										<i class="ion-md-trash text-base text-red-400"></i>
									</span>
								</button>
							</div>
							<div class="field w-full">
								<div class="control w-full">
									<InputTextArea @bind-Value="media.AltText" class="textarea w-full is-small !rounded-lg neoInput"
													 placeholder="@Localizer["Alternative text"]" rows="1" />
								</div>
							</div>
						</div>
					</div>
					break;
				case MediaType.Video:
				case MediaType.Documents:
					<div class="flex items-center space-x-3 align-center rounded-xl p-3 md:p-4 neomorph is-nxxsmall">
						<span>
							<i class="text-2xl @MessageForm.MediaType.GetMediaTypeIcon()"></i>
						</span>
						<div class="flex flex-col w-full space-y-1">
							<p class="text-xs md:text-sm break-all">
								<b>@media.FileName</b>
							</p>
							<p class="text-xs break-all">
								<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(Localizer._pLocalizer)
							</p>
						</div>
						<button class="button is-small is-rounded neoBtnSmall" @onclick="() => RemoveFile(media)" type="button">
							<span class="icon">
								<i class="ion-md-trash text-base text-red-400"></i>
							</span>
						</button>
					</div>
					break;
				case MediaType.Audio:
					<div class="flex items-center space-x-3 align-center rounded-xl p-3 md:p-4 neomorph is-nxxsmall">
						<span>
							<i class="text-2xl @MessageForm.MediaType.GetMediaTypeIcon()"></i>
						</span>
						<div class="flex flex-col w-full space-y-1">
							<p class="text-xs md:text-sm break-all">
								<b>@media.FileName</b>
							</p>
							<p class="text-xs break-all">
								<i class="ion-md-code"></i> @media.ContentType <i class="ion-md-fitness"></i> @media.Size.GetFileSize(Localizer._pLocalizer)
							</p>
							<audio controls="controls" class="w-full max-h-8">
								<source src="@media.Base64Preview" type="@media.ContentType">
							</audio>
						</div>
						<button class="button is-small is-rounded neoBtnSmall" @onclick="() => RemoveFile(media)" type="button">
							<span class="icon">
								<i class="ion-md-trash text-base text-red-400"></i>
							</span>
						</button>
					</div>
					break;
			}
		}

	</div>

	@if (fileInputErrorMessage is { Length: > 0 })
	{
		<div class="help is-danger p-1 md:p-2 mb-3 rounded-xl neomorphInset is-nxxsmall">
			@((MarkupString)fileInputErrorMessage)
		</div>
	}

	<div class="flex justify-between space-x-3 h-[30px]">
		<div class="flex space-x-3">
			<DropdownButton CssDirection="is-left" IsOpen="MessageForm.IsScopeOptionsOpen">
				<DropdownTrigger>
					<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.IsScopeOptionsOpen, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="OpenCloseMessageType"
									title="@string.Format(Localizer["Message scope type: {0}"], Localizer[MessageType.Direct.ToString()])" type="button">
						<span class="icon">
							<i class="@MessageForm.MessageType.GetMessageTypeIcon() text-base"></i>
						</span>
					</button>
				</DropdownTrigger>
				<DropdownContent>
					<div class="flex space-x-3 px-2">
						<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.MessageType is MessageType.Direct, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="() => UpdateMessageType(MessageType.Direct)"
										title="@Localizer[MessageType.Direct.ToString()]" type="button">
							<span class="icon">
								<i class="ion-md-paper-plane text-base"></i>
							</span>
						</button>
						<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.MessageType is MessageType.FollowersOnly, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="() => UpdateMessageType(MessageType.FollowersOnly)"
										title="@Localizer[MessageType.FollowersOnly.ToString()]" type="button">
							<span class="icon">
								<i class="ion-md-lock text-base"></i>
							</span>
						</button>
						<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.MessageType is MessageType.Unlisted, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="() => UpdateMessageType(MessageType.Unlisted)"
										title="@Localizer[MessageType.Unlisted.ToString()]" type="button">
							<span class="icon">
								<i class="ion-md-unlock text-base"></i>
							</span>
						</button>
						<button class="button is-small is-rounded @SUtility.IfTrueThen(MessageForm.MessageType is MessageType.Public, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="() => UpdateMessageType(MessageType.Public)"
										title="@Localizer[MessageType.Public.ToString()]" type="button">
							<span class="icon">
								<i class="ion-md-globe text-base"></i>
							</span>
						</button>
					</div>
				</DropdownContent>
			</DropdownButton>

			<div class="file is-small">
				<label class="file-label overflow-visible rounded-full neoBtnSmall h-[30px]">
					<InputFile accept="@acceptedFilesTypes" class="file-input" multiple="@ShouldHaveMultipleUpload()" OnChange="OnFileChange" disabled="@ShouldDisableUpload()" />
					<span class="file-cta">
						<span class="file-icon @SUtility.IfTrueThen(MessageForm.Media.Count == 0, "mr-0")">
							<i class="ion-md-attach text-base"></i>
						</span>
						@if (MessageForm.Media.Count != 0)
						{
							<span class="file-label">+@MessageForm.Media.Count</span>
						}
					</span>
				</label>
			</div>

			<div class="field">
				<div class="control has-icons-left">
					<div class="select is-small is-rounded neoSelect">
						<InputSelect TValue="MediaType" Value="MessageForm.MediaType" ValueChanged="v => OnMediaTypeChanged(v)" ValueExpression="() => MessageForm.MediaType" disabled="@(MessageForm.Media.Count > 0)">
							@foreach (var mediaType in Enum.GetValues<MediaType>())
							{
								<option value="@mediaType">@Localizer[mediaType.ToString()]</option>
							}
						</InputSelect>
					</div>
					<span class="icon is-small is-left">
						<i class="@MessageForm.MediaType.GetMediaTypeIcon()"></i>
					</span>
				</div>
			</div>

			<div class="field">
				<div class="control has-icons-left">
					<div class="select is-small is-rounded neoSelect">
						<InputSelect TValue="ContentType" Value="MessageForm.ContentType" ValueChanged="v => OnContentTypeChanged(v)" ValueExpression="() => MessageForm.ContentType">
							@foreach (var contentType in Enum.GetValues<ContentType>())
							{
								<option value="@contentType">@Localizer[contentType.ToString()]</option>
							}
						</InputSelect>
					</div>
					<span class="icon is-small is-left">
						<i class="@MessageForm.ContentType.GetContentTypeIcon()"></i>
					</span>
					<div class="help is-danger">
						<ValidationMessage For="() => MessageForm.ContentType" />
					</div>
				</div>
			</div>

			@if (showPreviewButton)
			{
				<button class="button is-small is-rounded @SUtility.IfTrueThen(isPreviewOpen, "neoBtnSmallInsetPlain", "neoBtnSmall")" @onclick="OnOpenClosePreview"
							title="@Localizer["Show preview"]" type="button">
					<span class="icon">
						<i class="@SUtility.IfTrueThen(isPreviewOpen, "ion-md-eye-off", "ion-md-eye") text-base"></i>
					</span>
				</button>
			}

		</div>

		<div class="flex space-x-3">

			<button class="button is-small is-rounded has-icons-right neoBtnSmall" type="submit">
				<span>@Localizer["Post"]</span>
				<span class="icon is-right">
					<i class="ion-md-send"></i>
				</span>
			</button>

		</div>

	</div>

</EditForm>

@code {
	[CascadingParameter] CascadingState CascadingState { get; set; }
	[Parameter] public Message AnsweringMessage { get; set; }
	[Parameter] public EventCallback<MessageForm> OnMessageSubmit { get; set; }
	MessageForm MessageForm { get; set; } = new();
	int totalCharacters { get; set; } = 0;
	string fileInputErrorMessage { get; set; }
	string contentError { get; set; }
	string acceptedFilesTypes { get; set; } = ".jpg,.jpeg,.png,.gif";
	bool showPreviewButton { get; set; } = false;
	bool isPreviewOpen { get; set; } = false;

	void OpenCloseMessageType()
	{
		MessageForm.IsScopeOptionsOpen = !MessageForm.IsScopeOptionsOpen;
	}

	void UpdateMessageType(MessageType messageType)
	{
		MessageForm.MessageType = messageType;
		MessageForm.IsScopeOptionsOpen = false;
	}

	protected override void OnInitialized()
	{
		if (AnsweringMessage != default)
		{
			MessageForm.Title = AnsweringMessage.Title;
			MessageForm.RootMessageId = AnsweringMessage.RootMessageId ?? AnsweringMessage.MessageId;
		}
	}

	bool ShouldDisableUpload()
	{
		switch (MessageForm.MediaType)
		{
			case MediaType.Images:
				return MessageForm.Media.Count == 5;
			case MediaType.Video:
			case MediaType.Audio:
				return MessageForm.Media.Count == 1;
			case MediaType.Documents:
				return MessageForm.Media.Count == 3;
			default:
				return true;
		}
	}

	bool ShouldHaveMultipleUpload()
	{
		return MessageForm.MediaType is MediaType.Images or MediaType.Documents;
	}

	async Task OnFileChange(InputFileChangeEventArgs eventArgs)
	{
		try
		{
			fileInputErrorMessage = string.Empty;
			var maximumFileCount = MessageForm.MediaType switch
			{
				MediaType.Images => 5,
				MediaType.Audio => 1,
				MediaType.Video => 1,
				MediaType.Documents => 3,
				_ => 0
			};
			if (eventArgs.FileCount > maximumFileCount)
			{
				fileInputErrorMessage = string.Format(Localizer["The maximum number of files accepted is {0}, but {1} were supplied."], maximumFileCount, eventArgs.FileCount);
				return;
			}
			if (eventArgs.FileCount + MessageForm.Media.Count > maximumFileCount)
			{
				fileInputErrorMessage = string.Format(Localizer["The maximum number of files accepted is {0}, but {1} were supplied."], maximumFileCount, $"{MessageForm.Media.Count}+{eventArgs.FileCount}");
				return;
			}
			var maxAllowedSize = MessageForm.MediaType switch
			{
				MediaType.Images => 3_145_728,
				MediaType.Audio => 5_242_880,
				MediaType.Video => 20_971_520,
				MediaType.Documents => 3_145_728,
				_ => 0
			};
			var uploadMedia = default(UploadMedia);
			using (var memStream = new MemoryStream())
				foreach (var file in eventArgs.GetMultipleFiles(maximumFileCount))
				{
					if (file.Name == default || file.ContentType == default) continue;
					if (MessageForm.Media.Any(m => m.FileName == file.Name)) continue;
					if (file.Size > maxAllowedSize)
					{
						fileInputErrorMessage += string.Format(Localizer["Supplied file \"{0}\" with size {1:N0}MBs exceeds the maximum of {2:N0}MBs."], file.Name, file.Size / 1_048_576, maxAllowedSize / 1_048_576) + "<br/>";
						continue;
					}

					uploadMedia = new()
						{
							FileName = file.Name,
							ContentType = file.ContentType,
							Size = file.Size
						};
					try
					{
						using (var imgStream = file.OpenReadStream(maxAllowedSize))
						{
							await imgStream.CopyToAsync(memStream);
							memStream.Position = 0;
							uploadMedia.Blob = memStream.ToArray();
							await memStream.FlushAsync();
						}
					}
					catch (IOException e)
					{
						fileInputErrorMessage = e.Message;
						continue;
					}
					catch (Exception e)
					{
						fileInputErrorMessage = e.Message;
						continue;
					}
					if (MessageForm.MediaType is MediaType.Images or MediaType.Audio)
						uploadMedia.Base64Preview = $"data:{uploadMedia.ContentType};base64,{Convert.ToBase64String(uploadMedia.Blob)}";

					MessageForm.Media.Add(uploadMedia);
				}
		}
		catch (Exception e)
		{
			fileInputErrorMessage = e.Message;
		}
	}

	void RemoveFile(UploadMedia media)
	{
		MessageForm.Media.Remove(media);
	}

	void OnTitleChanged(string value)
	{
		MessageForm.Title = value;
	}

	void ContentLengthChanged()
	{
		totalCharacters = MessageForm.Content?.Length ?? 0;
		StateHasChanged();
	}

	void OnContentTypeChanged(ContentType contentType)
	{
		MessageForm.ContentType = contentType;
		showPreviewButton = contentType is ContentType.Markdown or ContentType.HTML;
	}

	void OnMediaTypeChanged(MediaType mediaType)
	{
		MessageForm.MediaType = mediaType;
		acceptedFilesTypes = mediaType switch
		{
			MediaType.Images => ".jpg,.jpeg,.png,.gif",
			MediaType.Video => ".webm,.mp4,.m4v",
			MediaType.Audio => ".mp3,.wav,.flac,.m4a",
			MediaType.Documents => ".xlsx,.csv,.ppt,.odt",
			_ => default
		};
	}

	void OnOpenClosePreview()
	{
		isPreviewOpen = !isPreviewOpen;
	}

	async Task OnValidSubmit()
	{
		contentError = default;
		if ((MessageForm.Content is { Length: 0 } && MessageForm.Media.Count == 0))
		{
			contentError = Localizer["Missing content, either message or media"];
			return;
		}

		await OnMessageSubmit.InvokeAsync(MessageForm);
	}
}