@using AliasVault.Shared.Models.Spamok
@using AliasVault.Shared.Utilities
@using AliasVault.Shared.Core;
@using AliasVault.Client.Main.Components.Layout
@using AliasVault.RazorComponents.Services
@using Microsoft.Extensions.Localization
@inject JsInteropService JsInteropService
@inject GlobalNotificationService GlobalNotificationService
@inject IHttpClientFactory HttpClientFactory
@inject EmailService EmailService
@inject HttpClient HttpClient
@inject ConfirmModalService ConfirmModalService
@inject IStringLocalizerFactory LocalizerFactory

<div class="h-full flex flex-col bg-white border-l border-gray-200 dark:border-gray-700 rounded-l-lg">
    @if (Email != null)
    {
        <!-- Header -->
        <div class="p-4 border-b border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700">
            <div class="flex items-center justify-between mb-3">
                <h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100 truncate">
                    @if (IsSpamOk)
                    {
                        <a target="_blank" href="https://spamok.com/@(Email!.ToLocal)/@(Email!.Id)" class="hover:underline">@Email.Subject</a>
                    }
                    else
                    {
                        <span>@Email.Subject</span>
                    }
                </h2>
                <div class="flex items-center gap-2">
                    @if (GetAvailableModes().Count > 1)
                    {
                        <button @onclick="CycleViewMode"
                                title="@SharedLocalizer["EmailFormatSwitchTitle"]"
                                class="text-xs font-medium px-2 py-1 rounded text-gray-600 hover:text-gray-800 hover:bg-gray-200 dark:text-gray-300 dark:hover:text-gray-100 dark:hover:bg-gray-600">
                            @CurrentFormatLabel
                        </button>
                    }
                    <button @onclick="ShowDeleteConfirmation" id="delete-email" class="text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300">
                        <svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
                        </svg>
                    </button>
                </div>
            </div>
            <!-- 2-column layout for email details -->
            <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm text-gray-600 dark:text-gray-300">
                <div class="space-y-1">
                    <p><span class="font-medium">@Localizer["FromLabel"]</span> @(Email.FromLocal)@@@(Email.FromDomain)</p>
                    <p><span class="font-medium">@Localizer["ToLabel"]</span> @(Email.ToLocal)@@@(Email.ToDomain)</p>
                </div>
                <div class="space-y-1">
                    <p><span class="font-medium">@Localizer["DateLabel"]</span> @Email.DateSystem</p>
                    @if (!string.IsNullOrEmpty(CredentialName) && CredentialId != Guid.Empty)
                    {
                        <p><span class="font-medium">@SharedLocalizer["EmailItemLabel"]</span>
                            <button @onclick="@(() => OnCredentialClick.InvokeAsync(CredentialId))"
                                    class="text-blue-600 hover:underline dark:text-blue-400 cursor-pointer">
                                @CredentialName
                            </button>
                        </p>
                    }
                    else
                    {
                        <p><span class="font-medium">@SharedLocalizer["EmailItemLabel"]</span> <span class="text-gray-400 dark:text-gray-500">@SharedLocalizer["EmailItemNone"]</span></p>
                    }
                </div>
            </div>
        </div>

        <!-- Scrollable Content -->
        <div class="flex-1 flex flex-col overflow-hidden">
            <!-- Email Content - Takes remaining space -->
            <div class="flex-1 overflow-y-auto p-4">
                <div class="text-gray-700 dark:text-gray-300 h-full">
                    <iframe class="w-full h-full border-0" srcdoc="@EmailBody" sandbox="allow-popups allow-popups-to-escape-sandbox">
                    </iframe>
                </div>
            </div>

            @if (Email.Attachments?.Any() == true)
            {
                <!-- Attachments Section - Fixed height -->
                <div class="border-t border-gray-200 dark:border-gray-600 p-4 bg-gray-50 dark:bg-gray-800">
                    <h3 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">@Localizer["AttachmentsLabel"]</h3>
                    <div class="grid grid-cols-1 gap-2 max-h-32 overflow-y-auto">
                        @foreach (var attachment in Email.Attachments)
                        {
                            <div class="flex items-center space-x-2">
                                <svg class="w-4 h-4 text-gray-500 dark:text-gray-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"></path>
                                </svg>
                                <button @onclick="() => DownloadAttachment(attachment)"
                                        class="text-blue-600 hover:underline text-sm truncate dark:text-blue-400 attachment-link">
                                    (@(Math.Ceiling((double)attachment.Filesize / 1024)) KB) @attachment.Filename
                                </button>
                            </div>
                        }
                    </div>
                </div>
            }
        </div>
    }
    else
    {
        <div class="flex bg-gray-50 dark:bg-gray-700 items-center justify-center h-full text-gray-500 dark:text-gray-400">
            <div class="text-center">
                <svg class="mx-auto h-12 w-12 text-gray-300 dark:text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
                </svg>
                <p class="mt-2 text-sm">@Localizer["SelectEmailMessage"]</p>
            </div>
        </div>
    }
</div>

@code {
    private IStringLocalizer Localizer => LocalizerFactory.Create("Components.Main.Email.EmailPreview", "AliasVault.Client");

    private IStringLocalizer SharedLocalizer => LocalizerFactory.Create("SharedResources", "AliasVault.Client");

    /// <summary>
    /// The email to show in the preview.
    /// </summary>
    [Parameter]
    public EmailApiModel? Email { get; set; }

    /// <summary>
    /// Boolean that indicates if the email is from SpamOK public API.
    /// </summary>
    [Parameter]
    public bool IsSpamOk { get; set; }

    /// <summary>
    /// Callback when an email is deleted.
    /// </summary>
    [Parameter]
    public EventCallback<int> OnEmailDeleted { get; set; }

    /// <summary>
    /// The ID of the credential associated with this email.
    /// </summary>
    [Parameter]
    public Guid CredentialId { get; set; }

    /// <summary>
    /// The name of the credential associated with this email.
    /// </summary>
    [Parameter]
    public string CredentialName { get; set; } = string.Empty;

    /// <summary>
    /// Callback when credential is clicked.
    /// </summary>
    [Parameter]
    public EventCallback<Guid> OnCredentialClick { get; set; }

    /// <summary>
    /// The currently selected view mode.
    /// </summary>
    private EmailViewMode _viewMode = EmailViewMode.Html;

    /// <summary>
    /// The message body to display
    /// </summary>
    private string EmailBody = string.Empty;

    /// <summary>
    /// The id of the email whose body is currently rendered.
    /// </summary>
    private int? _renderedEmailId;

    /// <summary>
    /// Show confirmation modal before deleting email.
    /// </summary>
    private async Task ShowDeleteConfirmation()
    {
        if (Email == null)
        {
            return;
        }

        var result = await ConfirmModalService.ShowConfirmation(
            Localizer["DeleteEmailTitle"],
            Localizer["DeleteEmailConfirmation"],
            SharedLocalizer["Confirm"],
            SharedLocalizer["Cancel"]
        );

        if (result)
        {
            await DeleteEmail();
        }
    }

    /// <summary>
    /// Delete the current email.
    /// </summary>
    private async Task DeleteEmail()
    {
        if (Email == null)
        {
            return;
        }

        if (IsSpamOk)
        {
            await DeleteEmailSpamOk();
        }
        else
        {
            await DeleteEmailAliasVault();
        }
    }

    /// <summary>
    /// Delete the current email in SpamOk.
    /// </summary>
    private async Task DeleteEmailSpamOk()
    {
        if (Email == null)
        {
            return;
        }

        try
        {
            var client = HttpClientFactory.CreateClient("EmailClient");
            var request = new HttpRequestMessage(HttpMethod.Delete, $"https://api.spamok.com/v2/Email/{Email.ToLocal}/{Email.Id}");
            request.Headers.Add("X-Asdasd-Platform-Id", "av-web");
            request.Headers.Add("X-Asdasd-Platform-Version", AppInfo.GetFullVersion());

            var response = await client.SendAsync(request);

            if (response.IsSuccessStatusCode)
            {
                await OnEmailDeleted.InvokeAsync(Email.Id);
                GlobalNotificationService.AddSuccessMessage(Localizer["EmailDeletedSuccess"], true);
            }
            else
            {
                var errorMessage = await response.Content.ReadAsStringAsync();
                GlobalNotificationService.AddErrorMessage($"{Localizer["EmailDeleteFailed"]}: {errorMessage}", true);
            }
        }
        catch (Exception ex)
        {
            GlobalNotificationService.AddErrorMessage($"{Localizer["GenericError"]}: {ex.Message}", true);
        }
    }

    /// <summary>
    /// Delete the current email in AliasVault.
    /// </summary>
    private async Task DeleteEmailAliasVault()
    {
        if (Email == null)
        {
            return;
        }

        try
        {
            var response = await HttpClient.DeleteAsync($"v1/Email/{Email.Id}");
            if (response.IsSuccessStatusCode)
            {
                await OnEmailDeleted.InvokeAsync(Email.Id);
                GlobalNotificationService.AddSuccessMessage(Localizer["EmailDeletedSuccess"], true);
            }
            else
            {
                GlobalNotificationService.AddErrorMessage(Localizer["EmailDeleteFailed"], true);
            }
        }
        catch (Exception ex)
        {
            GlobalNotificationService.AddErrorMessage($"{Localizer["EmailDeleteFailed"]}: {ex.Message}", true);
        }
    }

    /// <inheritdoc />
    protected override async Task OnParametersSetAsync()
    {
        await base.OnParametersSetAsync();

        // Only (re)compute the rendered body when the email actually changes.
        if (Email?.Id == _renderedEmailId)
        {
            return;
        }

        _renderedEmailId = Email?.Id;

        if (Email != null)
        {
            // Pick an initial view mode based on what content is available.
            if (!string.IsNullOrWhiteSpace(Email.MessageHtml))
            {
                SetViewMode(EmailViewMode.Html);
            }
            else if (Email.MessagePlain != null)
            {
                SetViewMode(EmailViewMode.Plain);
            }
            else
            {
                EmailBody = Localizer["NoEmailBody"];
            }
        }
        else
        {
            EmailBody = string.Empty;
        }
    }

    /// <summary>
    /// Returns the list of view modes that have content for the current email,
    /// in display order (HTML, Plain, Source).
    /// </summary>
    private List<EmailViewMode> GetAvailableModes()
    {
        var modes = new List<EmailViewMode>();
        if (Email != null && !string.IsNullOrWhiteSpace(Email.MessageHtml))
        {
            modes.Add(EmailViewMode.Html);
        }

        if (Email?.MessagePlain != null)
        {
            modes.Add(EmailViewMode.Plain);
        }

        // Source shows the raw RFC 822 message captured by the SMTP service. Only offer it when
        // the server actually provided one — we never synthesise the source ourselves.
        if (!string.IsNullOrWhiteSpace(Email?.MessageSource))
        {
            modes.Add(EmailViewMode.Source);
        }
        return modes;
    }

    /// <summary>
    /// Label for the currently active view mode, used as the cycle button caption.
    /// </summary>
    private string CurrentFormatLabel => _viewMode switch
    {
        EmailViewMode.Html => SharedLocalizer["EmailFormatHtml"],
        EmailViewMode.Plain => SharedLocalizer["EmailFormatPlain"],
        EmailViewMode.Source => SharedLocalizer["EmailFormatSource"],
        _ => string.Empty,
    };

    /// <summary>
    /// Cycle to the next available view mode.
    /// </summary>
    private void CycleViewMode()
    {
        var modes = GetAvailableModes();
        if (modes.Count <= 1)
        {
            return;
        }

        var currentIndex = modes.IndexOf(_viewMode);
        var nextIndex = (currentIndex + 1) % modes.Count;
        SetViewMode(modes[nextIndex]);
    }

    /// <summary>
    /// Sets the email body based on the selected view mode.
    /// </summary>
    private void SetViewMode(EmailViewMode mode)
    {
        _viewMode = mode;
        if (Email == null)
        {
            return;
        }

        switch (mode)
        {
            case EmailViewMode.Html:
                if (!string.IsNullOrWhiteSpace(Email.MessageHtml))
                {
                    EmailBody = ConversionUtility.SanitizeAndPrepareEmailHtml(Email.MessageHtml);
                }
                else
                {
                    EmailBody = Localizer["NoEmailBody"];
                }

                break;
            case EmailViewMode.Plain:
                if (Email.MessagePlain != null)
                {
                    var escapedText = System.Net.WebUtility.HtmlEncode(Email.MessagePlain);
                    EmailBody = $"<pre style='font-family: system-ui, -apple-system, sans-serif; white-space: pre-wrap; word-wrap: break-word; margin: 0;'>{escapedText}</pre>";
                }
                else
                {
                    EmailBody = Localizer["NoEmailBody"];
                }

                break;
            case EmailViewMode.Source:
                if (!string.IsNullOrWhiteSpace(Email.MessageSource))
                {
                    var escapedSource = System.Net.WebUtility.HtmlEncode(Email.MessageSource);
                    EmailBody = $"<pre style='font-family: monospace; white-space: pre-wrap; word-wrap: break-word; margin: 0; font-size: 12px; line-height: 1.4;'>{escapedSource}</pre>";
                }
                else
                {
                    EmailBody = Localizer["NoEmailBody"];
                }

                break;
        }
    }

    /// <summary>
    /// Download an attachment.
    /// </summary>
    private async Task DownloadAttachment(AttachmentApiModel attachment)
    {
        try
        {
            if (IsSpamOk)
            {
                var client = HttpClientFactory.CreateClient("EmailClient");
                var request = new HttpRequestMessage(HttpMethod.Get, $"https://api.spamok.com/v2/Attachment/{Email!.Id}/{attachment.Id}/download");
                request.Headers.Add("X-Asdasd-Platform-Id", "av-web");
                request.Headers.Add("X-Asdasd-Platform-Version", AppInfo.GetFullVersion());

                var response = await client.SendAsync(request);
                if (response.IsSuccessStatusCode)
                {
                    var bytes = await response.Content.ReadAsByteArrayAsync();
                    await JsInteropService.DownloadFileFromStream(attachment.Filename, bytes);
                }
                else
                {
                    GlobalNotificationService.AddErrorMessage(Localizer["AttachmentDownloadFailed"], true);
                }
            }
            else
            {
                var response = await HttpClient.GetAsync($"v1/Email/{Email!.Id}/attachments/{attachment.Id}");

                if (response.IsSuccessStatusCode)
                {
                    // Get attachment bytes from API.
                    var bytes = await response.Content.ReadAsByteArrayAsync();

                    // Decrypt the attachment locally with email's encryption key.
                    var decryptedBytes = await EmailService.DecryptEmailAttachment(Email, bytes);

                    // Offer the decrypted attachment as download to the user's browser.
                    if (decryptedBytes != null)
                    {
                        await JsInteropService.DownloadFileFromStream(attachment.Filename, decryptedBytes);
                    }
                }
                else
                {
                    GlobalNotificationService.AddErrorMessage(Localizer["AttachmentDownloadFailed"], true);
                }
            }
        }
        catch (Exception ex)
        {
            GlobalNotificationService.AddErrorMessage($"{Localizer["AttachmentDownloadError"]}: {ex.Message}", true);
        }
    }
}
