@page "/items/create"
@page "/items/{id:guid}/edit"
@inherits MainBase
@inject ItemService ItemService
@inject IJSRuntime JSRuntime
@inject AliasVault.Client.Services.QuickCreateStateService QuickCreateStateService
@using AliasVault.Client.Services.JsInterop.Models
@using AliasVault.Client.Main.Components.Items
@using AliasVault.Client.Main.Components.Forms
@using Microsoft.Extensions.Localization
@using AliasClientDb
@using AliasClientDb.Models
@implements IAsyncDisposable

<PageHeader
    BreadcrumbItems="@BreadcrumbItems"
    Title="@(EditMode ? Localizer["EditItemTitle"] : Localizer["AddItemTitle"])"
    Description="@(EditMode ? Localizer["EditItemDescription"] : Localizer["AddItemDescription"])">
    <CustomActions>
        <ConfirmButton OnClick="TriggerFormSubmit">@Localizer["SaveItemButton"]</ConfirmButton>
        <CancelButton OnClick="Cancel">@SharedLocalizer["Cancel"]</CancelButton>
    </CustomActions>
</PageHeader>

@if (Loading)
{
    <LoadingIndicator />
}
else
{
    <EditForm @ref="EditFormRef" Model="Obj" OnValidSubmit="SaveAlias">
        <DataAnnotationsValidator />
        <div class="grid grid-cols-1 px-4 pt-6 md:grid-cols-2 lg:grid-cols-3 md:gap-4 dark:bg-gray-900">
            <div class="col-span-1 md:col-span-1 lg:col-span-1">
                @* Item Type Selector *@
                <ItemTypeSelector
                    SelectedType="@Obj.ItemType"
                    SelectedTypeChanged="HandleItemTypeChange"
                    IsEditMode="@EditMode"
                    ShowDropdown="@ShowTypeDropdown"
                    ShowDropdownChanged="@((show) => ShowTypeDropdown = show)"
                    OnRegenerateAlias="@GenerateRandomAlias" />

                @* Service/Name Section - Always shown *@
                <div class="p-4 mb-4 bg-white border-2 border-primary-600 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
                    <h3 class="mb-4 text-xl font-semibold dark:text-white">@Localizer["ServiceSectionHeader"]</h3>
                    <div class="grid gap-6">
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="service-name" Label="@Localizer["ServiceNameLabel"]" Placeholder="@Localizer["ServiceNamePlaceholder"]" @bind-Value="Obj.ServiceName"></EditFormRow>
                            <ValidationMessage For="() => Obj.ServiceName"/>
                            @* Folder Selector - below name field *@
                            <FolderSelector @bind-SelectedFolderId="Obj.FolderId" />
                        </div>
                        @* URL field - only for Login and Alias types (multi-value) *@
                        @if (ShouldShowField(FieldKey.LoginUrl))
                        {
                            <div class="col-span-6 sm:col-span-3">
                                <MultiValueFormRow
                                    Id="service-url"
                                    Label="@Localizer["ServiceUrlLabel"]"
                                    Values="@GetUrlValues()"
                                    ValuesChanged="OnUrlValuesChanged"
                                    OnFocus="OnFocusUrlInput" />
                            </div>
                        }
                    </div>
                </div>

                @* TOTP Codes Section - Only for Login/Alias types when visible *@
                @if (Show2FA && HasLoginFields())
                {
                    <div class="col-span-1 md:col-span-1 lg:col-span-1">
                        <TotpCodes TotpCodeList="@Obj.TotpCodes" TotpCodesChanged="HandleTotpCodesChanged" CanRemove="@CanRemove2FASection()" OnRemove="Remove2FASection" />
                    </div>
                }

                @* Notes Section - When visible (left side for non-Note types) *@
                @if (ShouldShowField(FieldKey.NotesContent) && Obj.ItemType != ItemType.Note)
                {
                    <div class="col-span-1 md:col-span-1 lg:col-span-1">
                        <RemovableSection CanRemove="@CanRemoveField(FieldKey.NotesContent)" OnRemove="() => RemoveOptionalField(FieldKey.NotesContent)">
                            <div class="col-span-6 sm:col-span-3">
                                <EditFormRow Type="textarea" Id="notes" Label="@Localizer["NotesLabel"]" LabelStyle="EditFormRow.FormLabelStyle.Header" @bind-Value="Obj.GetField(FieldKey.NotesContent)!.Value"></EditFormRow>
                            </div>
                        </RemovableSection>
                    </div>
                }

                @* Attachments Section - When visible *@
                @if (ShowAttachments)
                {
                    <div class="col-span-1 md:col-span-1 lg:col-span-1">
                        <RemovableSection Title="@Localizer["AttachmentsSectionHeader"]" CanRemove="@CanRemoveAttachmentsSection()" OnRemove="RemoveAttachmentsSection">
                            <div class="col-span-6 sm:col-span-3">
                                <AttachmentUploader
                                    Attachments="@Obj.Attachments"
                                    AttachmentsChanged="@HandleAttachmentsChanged" />
                            </div>
                        </RemovableSection>
                    </div>
                }

                @* Add Field Menu - Left column (visible only on lg screens when right column is also shown) *@
                <div class="hidden lg:block mb-4">
                    <AddFieldMenu
                        OptionalSystemFields="@GetOptionalSystemFields()"
                        VisibleFieldKeys="@GetVisibleFieldKeys()"
                        Show2FA="@Show2FA"
                        ShowAttachments="@ShowAttachments"
                        HasLoginFields="@HasLoginFields()"
                        CustomFieldCount="@Obj.GetCustomFields().Count"
                        OnAddSystemField="AddOptionalField"
                        OnAddCustomField="AddCustomField"
                        OnAdd2FA="Add2FASection"
                        OnAddAttachments="AddAttachmentsSection" />
                </div>
            </div>

            <div class="col-span-1 md:col-span-1 lg:col-span-2">
                @* Login Details Section - For Login and Alias types *@
                @if (HasLoginFields())
                {
                    <div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800 overflow-visible">
                        <h3 class="mb-4 text-xl font-semibold dark:text-white flex items-center gap-2">
                            <span>@Localizer["LoginDetailsSectionHeader"]</span>
                            @if (Obj.ItemType == ItemType.Login && !ShouldShowField(FieldKey.LoginEmail))
                            {
                                <button type="button" @onclick="() => AddOptionalField(FieldKey.LoginEmail)" @onclick:preventDefault="true"
                                        class="inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded-full transition-colors focus:outline-none text-gray-500 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 border border-dashed border-gray-300 dark:border-gray-600 hover:border-primary-400 dark:hover:border-primary-500">
                                    <svg class="w-2.5 h-2.5 -ml-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
                                        <line x1="12" y1="5" x2="12" y2="19" />
                                        <line x1="5" y1="12" x2="19" y2="12" />
                                    </svg>
                                    <span>@SharedLocalizer["Email"]</span>
                                </button>
                            }
                        </h3>
                        <div class="grid gap-6">
                            @if (EditMode && Obj.Passkeys != null && Obj.Passkeys.Any())
                            {
                                var passkey = Obj.Passkeys.First();
                                @* With passkey: Username, Passkey, Email, Password *@
                                <div class="col-span-6">
                                    <EditUsernameFormRow Id="username" Label="@Localizer["UsernameLabel"]" @bind-Value="Obj.GetField(FieldKey.LoginUsername)!.Value" OnGenerateNewUsername="GenerateRandomUsername"></EditUsernameFormRow>
                                </div>
                                @if (!PasskeyMarkedForDeletion)
                                {
                                    <div class="col-span-6">
                                        <div class="p-3 rounded-lg bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700">
                                            <div class="flex items-start gap-3">
                                                <svg class="w-5 h-5 text-gray-600 dark:text-gray-400 mt-0.5 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                                    <path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4" />
                                                </svg>
                                                <div class="flex-1">
                                                    <div class="mb-1 flex items-center justify-between">
                                                        <span class="text-sm font-semibold text-gray-900 dark:text-white">@Localizer["PasskeyLabel"]</span>
                                                        <button type="button" @onclick="MarkPasskeyForDeletion" class="text-red-600 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300" title="@Localizer["DeletePasskeyButton"]">
                                                            <svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                                                <polyline points="3 6 5 6 21 6" />
                                                                <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
                                                                <line x1="10" y1="11" x2="10" y2="17" />
                                                                <line x1="14" y1="11" x2="14" y2="17" />
                                                            </svg>
                                                        </button>
                                                    </div>
                                                    <div class="space-y-1 mb-2">
                                                        @if (!string.IsNullOrWhiteSpace(passkey.RpId))
                                                        {
                                                            <div>
                                                                <span class="text-xs text-gray-500 dark:text-gray-400">@Localizer["PasskeySiteLabel"]: </span>
                                                                <span class="text-sm text-gray-900 dark:text-white">@passkey.RpId</span>
                                                            </div>
                                                        }
                                                        @if (!string.IsNullOrWhiteSpace(passkey.DisplayName))
                                                        {
                                                            <div>
                                                                <span class="text-xs text-gray-500 dark:text-gray-400">@Localizer["PasskeyDisplayNameLabel"]: </span>
                                                                <span class="text-sm text-gray-900 dark:text-white">@passkey.DisplayName</span>
                                                            </div>
                                                        }
                                                    </div>
                                                    <p class="text-xs text-gray-600 dark:text-gray-400">
                                                        @Localizer["PasskeyHelpText"]
                                                    </p>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                }
                                else
                                {
                                    <div class="col-span-6">
                                        <div class="p-3 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800">
                                            <div class="flex items-start gap-3">
                                                <svg class="w-5 h-5 text-red-600 dark:text-red-400 mt-0.5 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                                    <path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4" />
                                                </svg>
                                                <div class="flex-1">
                                                    <div class="mb-1 flex items-center justify-between">
                                                        <span class="text-sm font-semibold text-red-900 dark:text-red-100">@Localizer["PasskeyMarkedForDeletion"]</span>
                                                        <button type="button" @onclick="UndoPasskeyDeletion" class="text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300" title="@Localizer["UndoButton"]">
                                                            <svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                                                <path d="M3 7v6h6" />
                                                                <path d="M21 17a9 9 0 00-9-9 9 9 0 00-6 2.3L3 13" />
                                                            </svg>
                                                        </button>
                                                    </div>
                                                    <p class="text-xs text-red-800 dark:text-red-200">
                                                        @Localizer["PasskeyWillBeDeleted"]
                                                    </p>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                }
                                <div class="col-span-6">
                                    <EmailDomainField Id="email"
                                                      @bind-Value="Obj.GetField(FieldKey.LoginEmail)!.Value"
                                                      DefaultToEmailMode="@(Obj.ItemType == ItemType.Login)"
                                                      OnGenerateAlias="@(Obj.ItemType == ItemType.Alias ? HandleGenerateAliasEmail : HandleGenerateRandomEmail)"></EmailDomainField>
                                </div>
                                <div class="col-span-6">
                                    <EditPasswordFormRow Id="password" Label="@Localizer["PasswordLabel"]" @bind-Value="Obj.GetField(FieldKey.LoginPassword)!.Value" ShowPassword="IsPasswordVisible"></EditPasswordFormRow>
                                </div>
                            }
                            else
                            {
                                @* Without passkey: Email (optional add for Login), Username, Password *@
                                @if (ShouldShowField(FieldKey.LoginEmail))
                                {
                                    <div class="col-span-6">
                                        @if (CanRemoveField(FieldKey.LoginEmail))
                                        {
                                            <EmailDomainField Id="email"
                                                              @bind-Value="Obj.GetField(FieldKey.LoginEmail)!.Value"
                                                              DefaultToEmailMode="@(Obj.ItemType == ItemType.Login)"
                                                              OnRemove="@(() => RemoveOptionalField(FieldKey.LoginEmail))"
                                                              OnGenerateAlias="@(Obj.ItemType == ItemType.Alias ? HandleGenerateAliasEmail : HandleGenerateRandomEmail)"></EmailDomainField>
                                        }
                                        else
                                        {
                                            <EmailDomainField Id="email"
                                                              @bind-Value="Obj.GetField(FieldKey.LoginEmail)!.Value"
                                                              DefaultToEmailMode="@(Obj.ItemType == ItemType.Login)"
                                                              OnGenerateAlias="@(Obj.ItemType == ItemType.Alias ? HandleGenerateAliasEmail : HandleGenerateRandomEmail)"></EmailDomainField>
                                        }
                                    </div>
                                }

                                <div class="col-span-6">
                                    <EditUsernameFormRow Id="username" Label="@Localizer["UsernameLabel"]" @bind-Value="Obj.GetField(FieldKey.LoginUsername)!.Value" OnGenerateNewUsername="GenerateRandomUsername"></EditUsernameFormRow>
                                </div>
                                <div class="col-span-6">
                                    <EditPasswordFormRow Id="password" Label="@Localizer["PasswordLabel"]" @bind-Value="Obj.GetField(FieldKey.LoginPassword)!.Value" ShowPassword="IsPasswordVisible"></EditPasswordFormRow>
                                </div>
                            }
                        </div>
                    </div>
                }

                @* Alias Identity Section - For Alias type *@
                @if (Obj.ItemType == ItemType.Alias)
                {
                    <div class="col-span-1 md:col-span-1 lg:col-span-2">
                        <div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
                            <h3 class="mb-4 text-xl font-semibold dark:text-white">@Localizer["AliasSectionHeader"]</h3>
                            <div class="mb-4">
                                <Button OnClick="HandleGenerateOrClearAlias" Color="@(HasAliasValues() ? "secondary" : "primary")" AdditionalClasses="@GetToggleButtonClasses()">
                                    <svg class='w-5 h-5 inline-block' viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                                        @if (HasAliasValues())
                                        {
                                            <path d="M18 6L6 18M6 6l12 12"/>
                                        }
                                        else
                                        {
                                            <rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
                                            <circle cx="8" cy="8" r="1"/>
                                            <circle cx="16" cy="8" r="1"/>
                                            <circle cx="12" cy="12" r="1"/>
                                            <circle cx="8" cy="16" r="1"/>
                                            <circle cx="16" cy="16" r="1"/>
                                        }
                                    </svg>
                                    @(HasAliasValues() ? Localizer["ClearAliasFieldsButton"] : Localizer["GenerateRandomAliasButton"])
                                </Button>
                            </div>
                            <div class="grid gap-6">
                                <div class="col-span-6 sm:col-span-3">
                                    <EditFormRow Id="first-name" Label="@Localizer["FirstNameLabel"]" @bind-Value="Obj.GetField(FieldKey.AliasFirstName)!.Value"></EditFormRow>
                                </div>
                                <div class="col-span-6 sm:col-span-3">
                                    <EditFormRow Id="last-name" Label="@Localizer["LastNameLabel"]" @bind-Value="Obj.GetField(FieldKey.AliasLastName)!.Value"></EditFormRow>
                                </div>
                                <div class="col-span-6 sm:col-span-3">
                                    <EditFormRow Id="gender" Label="@Localizer["GenderLabel"]" @bind-Value="Obj.GetField(FieldKey.AliasGender)!.Value"></EditFormRow>
                                </div>
                                <div class="col-span-6 sm:col-span-3">
                                    <EditFormRow Id="birthdate" Label="@Localizer["BirthDateLabel"]" @bind-Value="Obj.GetField(FieldKey.AliasBirthdate)!.Value"></EditFormRow>
                                </div>
                            </div>
                        </div>
                    </div>
                }

                @* Credit Card Section - For CreditCard type *@
                @if (Obj.ItemType == ItemType.CreditCard)
                {
                    <div class="col-span-1 md:col-span-1 lg:col-span-2">
                        <div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
                            <h3 class="mb-4 text-xl font-semibold dark:text-white">@Localizer["CardDetailsSectionHeader"]</h3>
                            <div class="grid gap-6">
                                <div class="col-span-6">
                                    <EditFormRow Id="cardholder-name" Label="@Localizer["CardholderNameLabel"]" @bind-Value="Obj.GetField(FieldKey.CardCardholderName)!.Value"></EditFormRow>
                                </div>
                                <div class="col-span-6">
                                    <EditPasswordFormRow Id="card-number" Label="@Localizer["CardNumberLabel"]" @bind-Value="Obj.GetField(FieldKey.CardNumber)!.Value" ShowPassword="false" ShowGenerateButtons="false"></EditPasswordFormRow>
                                </div>
                                <div class="col-span-3">
                                    <EditFormRow Id="expiry-month" Label="@Localizer["ExpiryMonthLabel"]" Placeholder="MM" @bind-Value="Obj.GetField(FieldKey.CardExpiryMonth)!.Value"></EditFormRow>
                                </div>
                                <div class="col-span-3">
                                    <EditFormRow Id="expiry-year" Label="@Localizer["ExpiryYearLabel"]" Placeholder="YYYY" @bind-Value="Obj.GetField(FieldKey.CardExpiryYear)!.Value"></EditFormRow>
                                </div>
                                <div class="col-span-6 sm:col-span-3">
                                    <EditPasswordFormRow Id="card-cvv" Label="@Localizer["CardCvvLabel"]" @bind-Value="Obj.GetField(FieldKey.CardCvv)!.Value" ShowPassword="false" ShowGenerateButtons="false"></EditPasswordFormRow>
                                </div>
                                @if (ShouldShowField(FieldKey.CardPin))
                                {
                                    <div class="col-span-6 sm:col-span-3 relative">
                                        <EditPasswordFormRow Id="card-pin" Label="@Localizer["CardPinLabel"]" @bind-Value="Obj.GetField(FieldKey.CardPin)!.Value" ShowPassword="false"></EditPasswordFormRow>
                                        @if (CanRemoveField(FieldKey.CardPin))
                                        {
                                            <button type="button" @onclick="() => RemoveOptionalField(FieldKey.CardPin)" @onclick:preventDefault="true"
                                                    class="absolute top-0 right-0 text-gray-400 hover:text-red-500 transition-colors" title="@Localizer["RemoveField"]">
                                                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
                                                </svg>
                                            </button>
                                        }
                                    </div>
                                }
                            </div>
                        </div>
                    </div>
                }

                @* Notes Section - For Note type (main content area) *@
                @if (Obj.ItemType == ItemType.Note)
                {
                    <div class="col-span-1 md:col-span-1 lg:col-span-2">
                        <div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
                            <h3 class="mb-4 text-xl font-semibold dark:text-white">@Localizer["NotesLabel"]</h3>
                            <div class="grid gap-6">
                                <div class="col-span-6">
                                    <EditFormRow Type="textarea" Id="notes" Label="" @bind-Value="Obj.GetField(FieldKey.NotesContent)!.Value"></EditFormRow>
                                </div>
                            </div>
                        </div>
                    </div>
                }

                @* Custom Fields Section *@
                @{
                    var customFields = Obj.GetCustomFields();
                }
                @if (customFields.Any())
                {
                    <div class="col-span-1 md:col-span-1 lg:col-span-2">
                        <div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
                            <h3 class="mb-4 text-xl font-semibold dark:text-white">@Localizer["CustomFieldsSectionHeader"]</h3>
                            <div class="grid gap-6">
                                @foreach (var customField in customFields)
                                {
                                    <div class="col-span-6">
                                        <EditableFieldLabel
                                            HtmlFor="@($"custom-{customField.TempId ?? customField.FieldKey}")"
                                            Label="@customField.Label"
                                            LabelChanged="@((newLabel) => Obj.UpdateCustomFieldLabel(customField.FieldKey, newLabel))"
                                            OnDelete="@(() => Obj.RemoveCustomField(customField.FieldKey))" />
                                        @if (customField.FieldType == FieldType.TextArea)
                                        {
                                            <div class="relative">
                                                <textarea id="@($"custom-{customField.TempId ?? customField.FieldKey}")" style="height: 200px;" class="outline-0 shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white" @bind="customField.Value"></textarea>
                                            </div>
                                        }
                                        else if (customField.IsHidden || customField.FieldType == FieldType.Hidden || customField.FieldType == FieldType.Password)
                                        {
                                            <EditPasswordFormRow Id="@($"custom-{customField.TempId ?? customField.FieldKey}")" Label="" @bind-Value="customField.Value" ShowPassword="false"></EditPasswordFormRow>
                                        }
                                        else
                                        {
                                            <div class="relative">
                                                <input type="text" id="@($"custom-{customField.TempId ?? customField.FieldKey}")" autocomplete="off" class="outline-0 shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white" @bind="customField.Value" autocapitalize="off" autocorrect="off">
                                            </div>
                                        }
                                    </div>
                                }
                            </div>
                        </div>
                    </div>
                }

                @* Add Field Menu *@
                <div class="col-span-1 md:col-span-1 lg:col-span-2 mb-4">
                    <AddFieldMenu
                        OptionalSystemFields="@GetOptionalSystemFields()"
                        VisibleFieldKeys="@GetVisibleFieldKeys()"
                        Show2FA="@Show2FA"
                        ShowAttachments="@ShowAttachments"
                        HasLoginFields="@HasLoginFields()"
                        CustomFieldCount="@Obj.GetCustomFields().Count"
                        OnAddSystemField="AddOptionalField"
                        OnAddCustomField="AddCustomField"
                        OnAdd2FA="Add2FASection"
                        OnAddAttachments="AddAttachmentsSection" />
                </div>
            </div>
        </div>
        <button type="submit" class="hidden">@Localizer["SaveItemButton"]</button>
    </EditForm>
}

@code {
    private IStringLocalizer Localizer => LocalizerFactory.Create("Pages.Main.Items.AddEdit", "AliasVault.Client");

    /// <summary>
    /// Gets or sets the Credentials ID.
    /// </summary>
    [Parameter]
    public Guid? Id { get; set; }

    private bool EditMode { get; set; }
    private EditForm EditFormRef { get; set; } = null!;
    private bool Loading { get; set; } = true;
    private bool IsPasswordVisible { get; set; } = false;
    private bool PasskeyMarkedForDeletion { get; set; } = false;
    private bool ShowTypeDropdown { get; set; } = false;
    private bool Show2FA { get; set; } = false;
    private bool ShowAttachments { get; set; } = false;
    private bool Show2FAAddedManually { get; set; } = false;
    private bool ShowAttachmentsAddedManually { get; set; } = false;
    private ItemEdit Obj { get; set; } = new();
    private IJSObjectReference? Module;

    /// <summary>
    /// Fields that were manually added via the + menu.
    /// </summary>
    private HashSet<string> ManuallyAddedFields { get; set; } = [];

    /// <summary>
    /// Fields that initially had values when loaded (for edit mode).
    /// </summary>
    private HashSet<string> InitiallyVisibleFields { get; set; } = [];

    // Track last generated values to protect manual entries
    private string? LastGeneratedUsername { get; set; }
    private string? LastGeneratedPassword { get; set; }
    private string? LastGeneratedEmail { get; set; }

    /// <inheritdoc />
    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        QuickCreateStateService.OnChange -= OnQuickCreateStateChanged;
        await KeyboardShortcutService.UnregisterShortcutAsync("gc");
        if (Module is not null)
        {
            await Module.DisposeAsync();
        }
    }

    /// <inheritdoc />
    protected override void OnInitialized()
    {
        if (Id.HasValue)
        {
            EditMode = true;
        }
        else
        {
            EditMode = false;
        }
    }

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

        if (EditMode)
        {
            BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = Localizer["ViewItemBreadcrumb"], Url = $"/items/{Id}" });
            BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = Localizer["EditItemBreadcrumb"] });
        }
        else
        {
            BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = Localizer["AddNewItemBreadcrumb"] });
        }
    }

    /// <inheritdoc />
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (firstRender)
        {
            Module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./js/modules/newIdentityWidget.js");

            // Subscribe to quick create state changes so we can reinitialize
            // when the user triggers the widget while already on this page.
            QuickCreateStateService.OnChange += OnQuickCreateStateChanged;

            if (EditMode)
            {
                await LoadExistingCredential();
            }
            else
            {
                await ApplyQuickCreateState();
            }

            Loading = false;
            StateHasChanged();

            if (!EditMode)
            {
                await JsInteropService.FocusElementById("service-name");
            }
        }
    }

    /// <summary>
    /// Handles the quick create state change event when the user triggers the
    /// CreateNewIdentityWidget while already on the AddEdit page.
    /// </summary>
    private async void OnQuickCreateStateChanged()
    {
        await InvokeAsync(async () =>
        {
            // Ensure we are in create mode since quick create always creates new items.
            EditMode = false;

            await ApplyQuickCreateState();
            Loading = false;
            StateHasChanged();
            await JsInteropService.FocusElementById("service-name");
        });
    }

    /// <summary>
    /// Creates a new credential and applies any prefilled data from the QuickCreateStateService.
    /// </summary>
    private async Task ApplyQuickCreateState()
    {
        CreateNewCredential();

        // Reset manually added fields tracking for the fresh form.
        ManuallyAddedFields = [];
        InitiallyVisibleFields = [];

        // Use the state service to pre-fill form data
        if (!string.IsNullOrEmpty(QuickCreateStateService.ServiceName))
        {
            Obj.ServiceName = QuickCreateStateService.ServiceName;
        }

        if (!string.IsNullOrEmpty(QuickCreateStateService.ServiceUrl))
        {
            Obj.SetFieldValue(FieldKey.LoginUrl, QuickCreateStateService.ServiceUrl);
        }

        if (!string.IsNullOrEmpty(QuickCreateStateService.ItemType))
        {
            await HandleItemTypeChange(QuickCreateStateService.ItemType);
        }

        if (QuickCreateStateService.FolderId.HasValue)
        {
            Obj.FolderId = QuickCreateStateService.FolderId;
        }

        // Clear the state after using it
        QuickCreateStateService.ClearState();
    }

    /// <summary>
    /// Checks if the current item type has login-related fields.
    /// </summary>
    private bool HasLoginFields()
    {
        return Obj.ItemType == ItemType.Login || Obj.ItemType == ItemType.Alias;
    }

    /// <summary>
    /// Determines if a field should be shown based on item type and visibility rules.
    /// </summary>
    private bool ShouldShowField(string fieldKey)
    {
        // Check if field applies to current item type
        var fieldDef = SystemFieldRegistry.GetSystemField(fieldKey);
        if (fieldDef == null || !SystemFieldRegistry.FieldAppliesToType(fieldDef, Obj.ItemType))
        {
            return false;
        }

        // Check if manually added
        if (ManuallyAddedFields.Contains(fieldKey))
        {
            return true;
        }

        // Check if initially visible (edit mode)
        if (InitiallyVisibleFields.Contains(fieldKey))
        {
            return true;
        }

        // Check if it has a value
        if (Obj.HasFieldValue(fieldKey))
        {
            return true;
        }

        // Check if shown by default for this item type
        var config = fieldDef.ApplicableToTypes.GetValueOrDefault(Obj.ItemType);
        return config?.ShowByDefault ?? false;
    }

    /// <summary>
    /// Determines if a field can be removed (is an optional field).
    /// </summary>
    private bool CanRemoveField(string fieldKey)
    {
        // A field can be removed if it's an optional field for the current item type
        var fieldDef = SystemFieldRegistry.GetSystemField(fieldKey);
        if (fieldDef == null)
        {
            return false;
        }

        // Check if it's an optional field (not shown by default)
        var config = fieldDef.ApplicableToTypes.GetValueOrDefault(Obj.ItemType);
        return config != null && !config.ShowByDefault;
    }

    /// <summary>
    /// Gets the optional system fields for the current item type.
    /// </summary>
    private IEnumerable<SystemFieldDefinition> GetOptionalSystemFields()
    {
        return SystemFieldRegistry.GetOptionalFieldsForItemType(Obj.ItemType);
    }

    /// <summary>
    /// Gets the currently visible field keys.
    /// </summary>
    private HashSet<string> GetVisibleFieldKeys()
    {
        var keys = new HashSet<string>();

        foreach (var field in SystemFieldRegistry.GetFieldsForItemType(Obj.ItemType))
        {
            if (ShouldShowField(field.FieldKey))
            {
                keys.Add(field.FieldKey);
            }
        }

        return keys;
    }

    /// <summary>
    /// Adds an optional field.
    /// </summary>
    private void AddOptionalField(string fieldKey)
    {
        ManuallyAddedFields.Add(fieldKey);
        StateHasChanged();
    }

    /// <summary>
    /// Removes an optional field (hides it and clears the value).
    /// </summary>
    private void RemoveOptionalField(string fieldKey)
    {
        ManuallyAddedFields.Remove(fieldKey);
        InitiallyVisibleFields.Remove(fieldKey);
        Obj.SetFieldValue(fieldKey, string.Empty);
        StateHasChanged();
    }

    /// <summary>
    /// Adds the 2FA section.
    /// </summary>
    private void Add2FASection()
    {
        Show2FA = true;
        Show2FAAddedManually = true;

        // Restore any soft-deleted TOTP codes (undo previous removal)
        foreach (var totpCode in Obj.TotpCodes)
        {
            if (totpCode.IsDeleted)
            {
                totpCode.IsDeleted = false;
                totpCode.UpdatedAt = DateTime.UtcNow;
            }
        }

        StateHasChanged();
    }

    /// <summary>
    /// Removes the 2FA section and marks existing TOTP codes for deletion.
    /// </summary>
    private void Remove2FASection()
    {
        Show2FA = false;
        Show2FAAddedManually = false;

        // Mark all TOTP codes for deletion (soft delete for existing, remove new ones)
        foreach (var totpCode in Obj.TotpCodes.ToList())
        {
            if (totpCode.Id != Guid.Empty)
            {
                // Existing code - mark for soft delete
                totpCode.IsDeleted = true;
                totpCode.UpdatedAt = DateTime.UtcNow;
            }
            else
            {
                // New code - just remove from list
                Obj.TotpCodes.Remove(totpCode);
            }
        }

        StateHasChanged();
    }

    /// <summary>
    /// Checks if the 2FA section can be removed.
    /// Only allow removal when there's at least one TOTP code registered.
    /// </summary>
    private bool CanRemove2FASection()
    {
        return Obj.TotpCodes.Any(t => !t.IsDeleted);
    }

    /// <summary>
    /// Adds the attachments section.
    /// </summary>
    private void AddAttachmentsSection()
    {
        ShowAttachments = true;
        ShowAttachmentsAddedManually = true;

        // Restore any soft-deleted attachments (undo previous removal)
        foreach (var attachment in Obj.Attachments)
        {
            if (attachment.IsDeleted)
            {
                attachment.IsDeleted = false;
                attachment.UpdatedAt = DateTime.UtcNow;
            }
        }

        StateHasChanged();
    }

    /// <summary>
    /// Removes the attachments section and marks existing attachments for deletion.
    /// </summary>
    private void RemoveAttachmentsSection()
    {
        ShowAttachments = false;
        ShowAttachmentsAddedManually = false;

        // Mark all attachments for deletion (soft delete for existing, remove new ones)
        foreach (var attachment in Obj.Attachments.ToList())
        {
            if (attachment.Id != Guid.Empty)
            {
                // Existing attachment - mark for soft delete
                attachment.IsDeleted = true;
                attachment.UpdatedAt = DateTime.UtcNow;
            }
            else
            {
                // New attachment - just remove from list
                Obj.Attachments.Remove(attachment);
            }
        }

        StateHasChanged();
    }

    /// <summary>
    /// Checks if the attachments section can be removed (always true when visible).
    /// </summary>
    private bool CanRemoveAttachmentsSection()
    {
        return true;
    }

    /// <summary>
    /// Adds a custom field.
    /// </summary>
    private void AddCustomField((string Label, string FieldType) args)
    {
        Obj.AddCustomField(args.Label, args.FieldType);
        StateHasChanged();
    }

    /// <summary>
    /// Handles item type change.
    /// Clears field values that don't apply to the new item type.
    /// </summary>
    private async Task HandleItemTypeChange(string newType)
    {
        if (Obj.ItemType == newType)
        {
            return;
        }

        var oldType = Obj.ItemType;
        Obj.ItemType = newType;

        // Clear all system fields that don't apply to the new type
        foreach (var fieldDef in SystemFieldRegistry.Fields.Values)
        {
            if (!SystemFieldRegistry.FieldAppliesToType(fieldDef, newType))
            {
                Obj.SetFieldValue(fieldDef.FieldKey, string.Empty);
            }
        }

        // Clear manually added fields that don't apply to new type
        var fieldsToRemove = ManuallyAddedFields
            .Where(fk => {
                var def = SystemFieldRegistry.GetSystemField(fk);
                return def != null && !SystemFieldRegistry.FieldAppliesToType(def, newType);
            })
            .ToList();
        foreach (var fk in fieldsToRemove)
        {
            ManuallyAddedFields.Remove(fk);
        }

        // Clear initially visible fields that don't apply to new type
        var initialFieldsToRemove = InitiallyVisibleFields
            .Where(fk => {
                var def = SystemFieldRegistry.GetSystemField(fk);
                return def != null && !SystemFieldRegistry.FieldAppliesToType(def, newType);
            })
            .ToList();
        foreach (var fk in initialFieldsToRemove)
        {
            InitiallyVisibleFields.Remove(fk);
        }

        // Generate alias for Alias type in create mode
        if (newType == ItemType.Alias && !EditMode && !HasAliasValues())
        {
            await GenerateRandomAlias();
        }

        StateHasChanged();
    }

    /// <summary>
    /// Loads an existing credential for editing.
    /// </summary>
    private async Task LoadExistingCredential()
    {
        if (Id is null)
        {
            NavigateAwayWithError(Localizer["ItemNotExistError"]);
            return;
        }

        var item = await ItemService.LoadEntryAsync(Id.Value);
        if (item is null)
        {
            NavigateAwayWithError(Localizer["ItemNotExistError"]);
            return;
        }

        Obj = ItemEdit.FromEntity(item);

        // Track initially visible fields
        foreach (var fieldDef in SystemFieldRegistry.GetFieldsForItemType(Obj.ItemType))
        {
            if (Obj.HasFieldValue(fieldDef.FieldKey))
            {
                InitiallyVisibleFields.Add(fieldDef.FieldKey);
            }
        }

        // Show sections that have content
        Show2FA = Obj.TotpCodes.Any();
        ShowAttachments = Obj.Attachments.Any();

        // Set default URL if not set
        if (!Obj.HasFieldValue(FieldKey.LoginUrl))
        {
            Obj.SetFieldValue(FieldKey.LoginUrl, ItemService.DefaultServiceUrl);
        }
    }

    /// <summary>
    /// Creates a new item object.
    /// </summary>
    private Item CreateNewItemObject()
    {
        var item = new Item
        {
            ItemType = AliasClientDb.Models.ItemType.Login,
            FieldValues = new List<FieldValue>(),
            Attachments = new List<Attachment>(),
            TotpCodes = new List<TotpCode>(),
            Passkeys = new List<Passkey>()
        };

        // Don't pre-populate email for Login type - it's an optional field
        // Email will be populated when user switches to Alias type or manually adds the field

        return item;
    }

    /// <summary>
    /// Creates a new item object for editing.
    /// </summary>
    private void CreateNewCredential()
    {
        Obj = ItemEdit.FromEntity(CreateNewItemObject());

        Obj.SetFieldValue(FieldKey.AliasBirthdate, string.Empty);
        Obj.SetFieldValue(FieldKey.LoginUrl, ItemService.DefaultServiceUrl);
    }

    /// <summary>
    /// Adds an error message and navigates to the home page.
    /// </summary>
    private void NavigateAwayWithError(string errorMessage)
    {
        GlobalNotificationService.AddErrorMessage(errorMessage);
        NavigationManager.NavigateTo("/items", false, true);
    }

    /// <summary>
    /// Gets the URL values for the multi-value field.
    /// Ensures at least one entry exists.
    /// </summary>
    private List<string> GetUrlValues()
    {
        var field = Obj.GetField(FieldKey.LoginUrl);
        if (field == null)
        {
            return new List<string> { string.Empty };
        }

        // Return Values if populated, otherwise convert single Value
        if (field.Values != null && field.Values.Count > 0)
        {
            return field.Values;
        }

        return string.IsNullOrEmpty(field.Value)
            ? new List<string> { string.Empty }
            : new List<string> { field.Value };
    }

    /// <summary>
    /// Handles URL values change from the multi-value component.
    /// </summary>
    private void OnUrlValuesChanged(List<string> values)
    {
        Obj.SetFieldValues(FieldKey.LoginUrl, values);
        StateHasChanged();
    }

    /// <summary>
    /// When the URL input is focused, place cursor at the end of the default URL.
    /// </summary>
    private void OnFocusUrlInput((int Index, FocusEventArgs Args) e)
    {
        var urlValues = GetUrlValues();
        if (e.Index >= urlValues.Count)
        {
            return;
        }

        var currentUrl = urlValues[e.Index];
        if (currentUrl != ItemService.DefaultServiceUrl)
        {
            return;
        }

        Task.Delay(1).ContinueWith(_ =>
        {
            JSRuntime.InvokeVoidAsync("eval", $"document.getElementById('service-url-{e.Index}').setSelectionRange({ItemService.DefaultServiceUrl.Length}, {ItemService.DefaultServiceUrl.Length})");
        });
    }

    private void HandleAttachmentsChanged(List<Attachment> updatedAttachments)
    {
        Obj.Attachments = updatedAttachments;
        StateHasChanged();
    }

    private void HandleTotpCodesChanged(List<TotpCode> updatedTotpCodes)
    {
        Obj.TotpCodes = updatedTotpCodes;
        StateHasChanged();
    }

    private async Task HandleGenerateOrClearAlias()
    {
        if (HasAliasValues())
        {
            ClearAliasFields();
        }
        else
        {
            await GenerateRandomAlias();
        }
    }

    private void ClearAliasFields()
    {
        Obj.SetFieldValue(FieldKey.AliasFirstName, string.Empty);
        Obj.SetFieldValue(FieldKey.AliasLastName, string.Empty);
        Obj.SetFieldValue(FieldKey.AliasGender, string.Empty);
        Obj.SetFieldValue(FieldKey.AliasBirthdate, string.Empty);

        StateHasChanged();
    }

    private bool HasAliasValues()
    {
        return !string.IsNullOrWhiteSpace(Obj.GetFieldValue(FieldKey.AliasFirstName)) ||
               !string.IsNullOrWhiteSpace(Obj.GetFieldValue(FieldKey.AliasLastName)) ||
               !string.IsNullOrWhiteSpace(Obj.GetFieldValue(FieldKey.AliasGender)) ||
               !string.IsNullOrWhiteSpace(Obj.GetFieldValue(FieldKey.AliasBirthdate));
    }

    private string GetToggleButtonClasses()
    {
        var baseClasses = "flex items-center justify-center gap-1";
        if (HasAliasValues())
        {
            return $"{baseClasses} bg-gray-500 hover:bg-gray-600 text-white";
        }
        return baseClasses;
    }

    private async Task GenerateRandomAlias()
    {
        string currentUsername = Obj.GetFieldValue(FieldKey.LoginUsername);
        string currentPassword = Obj.GetFieldValue(FieldKey.LoginPassword);
        string currentEmail = Obj.GetFieldValue(FieldKey.LoginEmail);

        var generatedItem = await ItemService.GenerateRandomIdentityAsync(Obj.ToEntity());
        var generatedObj = ItemEdit.FromEntity(generatedItem);

        // Keep the current values if user has modified them
        Obj.SetFieldValue(FieldKey.LoginUsername, currentUsername);
        Obj.SetFieldValue(FieldKey.LoginPassword, currentPassword);
        Obj.SetFieldValue(FieldKey.LoginEmail, currentEmail);

        // Always update alias fields
        Obj.SetFieldValue(FieldKey.AliasFirstName, generatedObj.GetFieldValue(FieldKey.AliasFirstName));
        Obj.SetFieldValue(FieldKey.AliasLastName, generatedObj.GetFieldValue(FieldKey.AliasLastName));
        Obj.SetFieldValue(FieldKey.AliasGender, generatedObj.GetFieldValue(FieldKey.AliasGender));
        Obj.SetFieldValue(FieldKey.AliasBirthdate, generatedObj.GetFieldValue(FieldKey.AliasBirthdate));

        var generatedUsername = generatedObj.GetFieldValue(FieldKey.LoginUsername);
        var generatedPassword = generatedObj.GetFieldValue(FieldKey.LoginPassword);
        var generatedEmail = generatedObj.GetFieldValue(FieldKey.LoginEmail);

        if (string.IsNullOrWhiteSpace(currentUsername) || currentUsername == LastGeneratedUsername)
        {
            Obj.SetFieldValue(FieldKey.LoginUsername, generatedUsername);
            LastGeneratedUsername = generatedUsername;
        }

        if (string.IsNullOrWhiteSpace(currentPassword) || currentPassword == LastGeneratedPassword)
        {
            Obj.SetFieldValue(FieldKey.LoginPassword, generatedPassword);
            LastGeneratedPassword = generatedPassword;
            IsPasswordVisible = true;
        }

        if (string.IsNullOrWhiteSpace(currentEmail) || currentEmail == LastGeneratedEmail || currentEmail.StartsWith("@"))
        {
            Obj.SetFieldValue(FieldKey.LoginEmail, generatedEmail);
            LastGeneratedEmail = generatedEmail;
        }

        StateHasChanged();
    }

    /// <summary>
    /// Generate a new random username.
    /// </summary>
    private async Task GenerateRandomUsername()
    {
        var aliasFirstName = Obj.GetFieldValue(FieldKey.AliasFirstName);
        var aliasLastName = Obj.GetFieldValue(FieldKey.AliasLastName);
        var aliasBirthDate = Obj.GetFieldValue(FieldKey.AliasBirthdate);

        AliasVaultIdentity identity;
        if (string.IsNullOrWhiteSpace(aliasFirstName) && string.IsNullOrWhiteSpace(aliasLastName) && string.IsNullOrWhiteSpace(aliasBirthDate))
        {
            var randomIdentity = await ItemService.GenerateRandomIdentityAsync(CreateNewItemObject());
            var randomIdentityEdit = ItemEdit.FromEntity(randomIdentity);

            identity = new AliasVaultIdentity
            {
                FirstName = randomIdentityEdit.GetFieldValue(FieldKey.AliasFirstName),
                LastName = randomIdentityEdit.GetFieldValue(FieldKey.AliasLastName),
                BirthDate = randomIdentityEdit.GetFieldValue(FieldKey.AliasBirthdate),
                Gender = randomIdentityEdit.GetFieldValue(FieldKey.AliasGender),
                NickName = randomIdentityEdit.GetFieldValue(FieldKey.LoginUsername),
            };
        }
        else
        {
            identity = new AliasVaultIdentity
            {
                FirstName = aliasFirstName,
                LastName = aliasLastName,
                BirthDate = aliasBirthDate,
                Gender = Obj.GetFieldValue(FieldKey.AliasGender),
                NickName = Obj.GetFieldValue(FieldKey.LoginUsername),
            };
        }

        Obj.SetFieldValue(FieldKey.LoginUsername, await JsInteropService.GenerateRandomUsernameAsync(identity));
    }

    /// <summary>
    /// Generate an identity-based email alias (for Alias type email field).
    /// Uses the current alias field values (first name, last name, birthdate) to derive the email prefix,
    /// so the email stays consistent with the filled-in persona fields.
    /// </summary>
    private async Task HandleGenerateAliasEmail()
    {
        var firstName = Obj.GetFieldValue(FieldKey.AliasFirstName);
        var lastName = Obj.GetFieldValue(FieldKey.AliasLastName);

        string prefix;
        if (string.IsNullOrWhiteSpace(firstName) && string.IsNullOrWhiteSpace(lastName))
        {
            // No alias identity fields filled in, fall back to random prefix.
            prefix = await JsInteropService.GenerateRandomStringEmailPrefixAsync();
        }
        else
        {
            var identity = new AliasVaultIdentity
            {
                FirstName = firstName,
                LastName = lastName,
                BirthDate = Obj.GetFieldValue(FieldKey.AliasBirthdate),
                Gender = Obj.GetFieldValue(FieldKey.AliasGender),
                NickName = Obj.GetFieldValue(FieldKey.LoginUsername),
            };

            prefix = await JsInteropService.GenerateRandomEmailPrefixAsync(identity);
        }

        var defaultEmailDomain = DbService.Settings.DefaultEmailDomain;
        var email = !string.IsNullOrEmpty(defaultEmailDomain) ? $"{prefix}@{defaultEmailDomain}" : prefix;

        Obj.SetFieldValue(FieldKey.LoginEmail, email);
        StateHasChanged();
    }

    /// <summary>
    /// Generate a random-string email alias (for Login type email field).
    /// Uses random characters instead of identity-based prefixes since Login type
    /// has no persona fields to base the email on.
    /// </summary>
    private async Task HandleGenerateRandomEmail()
    {
        var prefix = await JsInteropService.GenerateRandomStringEmailPrefixAsync();
        var defaultEmailDomain = DbService.Settings.DefaultEmailDomain;
        var email = !string.IsNullOrEmpty(defaultEmailDomain) ? $"{prefix}@{defaultEmailDomain}" : prefix;

        Obj.SetFieldValue(FieldKey.LoginEmail, email);
        StateHasChanged();
    }

    /// <summary>
    /// Cancel the edit operation.
    /// </summary>
    private void Cancel()
    {
        NavigationManager.NavigateTo("/items/" + Id);
    }

    /// <summary>
    /// Trigger the form submit.
    /// </summary>
    private async Task TriggerFormSubmit()
    {
        if (EditFormRef.EditContext?.Validate() == false)
        {
            return;
        }

        await SaveAlias();
    }

    /// <summary>
    /// Marks the passkey for deletion.
    /// </summary>
    private void MarkPasskeyForDeletion()
    {
        PasskeyMarkedForDeletion = true;
        StateHasChanged();
    }

    /// <summary>
    /// Undoes the passkey deletion mark.
    /// </summary>
    private void UndoPasskeyDeletion()
    {
        PasskeyMarkedForDeletion = false;
        StateHasChanged();
    }

    /// <summary>
    /// Save the item to the database.
    /// </summary>
    private async Task SaveAlias()
    {
        GlobalLoadingSpinner.Show(Localizer["SavingVaultMessage"]);
        StateHasChanged();

        // Delete passkeys if marked for deletion
        if (PasskeyMarkedForDeletion && Obj.Passkeys != null && Obj.Passkeys.Any())
        {
            var context = await DbService.GetDbContextAsync();
            foreach (var passkey in Obj.Passkeys)
            {
                await ItemService.DeletePasskeyAsync(passkey.Id);
            }
            Obj.Passkeys.Clear();
        }

        if (EditMode)
        {
            if (Id is not null)
            {
                Id = await ItemService.UpdateEntryAsync(Obj.ToEntity());
            }
        }
        else
        {
            Id = await ItemService.InsertEntryAsync(Obj.ToEntity());
        }

        GlobalLoadingSpinner.Hide();
        StateHasChanged();

        if (Id is null || Id == Guid.Empty)
        {
            GlobalNotificationService.AddErrorMessage(Localizer["ErrorSavingItem"], true);
            return;
        }

        if (EditMode)
        {
            GlobalNotificationService.AddSuccessMessage(Localizer["ItemUpdatedSuccess"]);
        }
        else
        {
            GlobalNotificationService.AddSuccessMessage(Localizer["ItemCreatedSuccess"]);
        }

        NavigationManager.NavigateTo("/items/" + Id);
    }

}
