@page "/add-alias"
@page "/alias/{id:guid}/edit"
@inherits PageBase
@inject NavigationManager Navigation
@inject AliasService AliasService
@using AliasGenerators.Implementations
@using AliasGenerators.Password.Implementations
@using AliasVault.Shared.Models.WebApi
@using System.Globalization

@if (EditMode)
{
    <LayoutPageTitle>Edit alias</LayoutPageTitle>
}
else {
    <LayoutPageTitle>Add alias</LayoutPageTitle>
}

<div class="grid grid-cols-1 px-4 pt-6 xl:grid-cols-3 xl:gap-4 dark:bg-gray-900">
    <div class="mb-4 col-span-full xl:mb-2">
        <Breadcrumb BreadcrumbItems="BreadcrumbItems" />
        <div class="flex items-center justify-between">
            @if (EditMode)
            {
                <h1 class="text-xl font-semibold text-gray-900 sm:text-2xl dark:text-white">Edit alias</h1>
            }
            else {
                <h1 class="text-xl font-semibold text-gray-900 sm:text-2xl dark:text-white">Add alias</h1>
            }
        </div>
        @if (EditMode)
        {
            <p>Edit the existing alias below.</p>
        }
        else {
            <p>Create a new alias below.</p>
        }
    </div>
</div>

@if (Loading)
{
    <LoadingIndicator />
}
else
{
    <EditForm Model="Obj" OnValidSubmit="SaveAlias">
        <DataAnnotationsValidator />
        <div class="grid px-4 pt-6 lg:gap-4 dark:bg-gray-900">
            <div class="col">
                <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">Service</h3>
                    <div class="grid gap-6">
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="service-name" Label="Service Name" @bind-Value="Obj.ServiceName"></EditFormRow>
                            <ValidationMessage For="() => Obj.ServiceName"/>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="service-url" Label="Service URL" @bind-Value="Obj.ServiceUrl"></EditFormRow>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col">
                <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">Login credentials</h3>
                    <div class="mb-4">
                        <button type="button" class="px-4 py-2 text-white bg-blue-600 rounded-lg hover:bg-blue-700 focus:ring-4 focus:ring-blue-300 dark:bg-blue-500 dark:hover:bg-blue-600 dark:focus:ring-blue-800" @onclick="GenerateRandomIdentity">Generate Random Identity</button>
                        <button type="submit" class="px-4 py-2 text-white bg-green-600 rounded-lg hover:bg-green-700 focus:ring-4 focus:ring-green-300 dark:bg-green-500 dark:hover:bg-green-600 dark:focus:ring-green-800">Save Alias</button>
                        @if (IsIdentityLoading)
                        {
                            <p>Loading...</p>
                        }
                    </div>
                    <div class="grid gap-6">
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="email" Label="Email" @bind-Value="Obj.Identity.EmailPrefix"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="username" Label="Username" @bind-Value="Obj.Identity.NickName"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <div class="relative">
                                <EditFormRow Id="password" Label="Password" @bind-Value="Obj.Password.Value"></EditFormRow>
                                <button type="submit" class="text-white absolute end-1 bottom-1 bg-gray-700 hover:bg-gray-800 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium rounded-lg text-sm px-4 py-2 dark:bg-gray-600 dark:hover:bg-gray-700 dark:focus:ring-gray-800" @onclick="GenerateRandomPassword">(Re)generate Random Password</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="grid px-4 pt-6 lg:gap-4 dark:bg-gray-900">
            <div class="col">
                <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">Identity</h3>
                    <div class="grid gap-6">
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="first-name" Label="First Name" @bind-Value="Obj.Identity.FirstName"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="last-name" Label="Last Name" @bind-Value="Obj.Identity.LastName"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="gender" Label="Gender" @bind-Value="Obj.Identity.Gender"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="nickname" Label="Nick Name" @bind-Value="Obj.Identity.NickName"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="birthdate" Label="Birth Date" @bind-Value="Obj.Identity.BirthDate"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="street" Label="Address Street" @bind-Value="Obj.Identity.AddressStreet"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="city" Label="Address City" @bind-Value="Obj.Identity.AddressCity"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="state" Label="Address State" @bind-Value="Obj.Identity.AddressState"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="zipcode" Label="Address Zip Code" @bind-Value="Obj.Identity.AddressZipCode"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="country" Label="Address Country" @bind-Value="Obj.Identity.AddressCountry"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="hobbies" Label="Hobbies" @bind-Value="Obj.Identity.Hobbies"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="phone-mobile" Label="Phone Mobile" @bind-Value="Obj.Identity.PhoneMobile"></EditFormRow>
                        </div>
                        <div class="col-span-6 sm:col-span-3">
                            <EditFormRow Id="iban" Label="Bank Account IBAN" @bind-Value="Obj.Identity.BankAccountIBAN"></EditFormRow>
                        </div>
                    </div>
                </div>
            </div>
            <button type="submit" class="px-4 py-2 text-white bg-green-600 rounded-lg hover:bg-green-700 focus:ring-4 focus:ring-green-300 dark:bg-green-500 dark:hover:bg-green-600 dark:focus:ring-green-800">Save Alias</button>
        </div>
    </EditForm>

    @if (IsSaving)
    {
        <p>Saving...</p>
    }

}

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

    private bool EditMode { get; set; }
    private bool Loading { get; set; } = true;
    private AliasEdit Obj { get; set; } = new();
    private bool IsIdentityLoading { get; set; }
    private bool IsSaving { get; set; }

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

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

        if (EditMode)
        {
            BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Edit alias" });
        }
        else
        {
            BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Add new alias" });
        }
    }

    /// <inheritdoc />
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            if (EditMode)
            {
                if (Id is null)
                {
                    // Error loading alias.
                    GlobalNotificationService.AddErrorMessage("This alias does not exist (anymore). Please try again.");
                    NavigationManager.NavigateTo("/", false, true);
                    return;
                }

                // Load existing Obj, retrieve from service
                var alias = await AliasService.LoadAliasAsync(Id.Value);
                if (alias is null)
                {
                    // Error loading alias.
                    GlobalNotificationService.AddErrorMessage("This alias does not exist (anymore). Please try again.");
                    NavigationManager.NavigateTo("/", false, true);
                    return;
                }

                Obj = AliasToAliasEdit(alias);
            }
            else
            {
                // Create new Obj
                var alias = new Alias();
                alias.Identity = new Shared.Models.WebApi.Identity();
                alias.Service = new Shared.Models.WebApi.Service();
                alias.Password = new Shared.Models.WebApi.Password();

                Obj = AliasToAliasEdit(alias);
            }

            // Hide loading spinner
            Loading = false;
            // Force re-render invoke so the charts can be rendered
            StateHasChanged();
        }
    }

    private async Task GenerateRandomIdentity()
    {
        IsIdentityLoading = true;
        StateHasChanged();

        // Generate a random identity using the IIdentityGenerator implementation.
        var identity = await AliasService.GenerateRandomIdentityAsync();

        // Generate random values for the Identity properties
        Obj.Identity.FirstName = identity.FirstName;
        Obj.Identity.LastName = identity.LastName;
        Obj.Identity.NickName = identity.NickName;
        Obj.Identity.Gender = identity.Gender == 1 ? "Male" : "Female";
        Obj.Identity.BirthDate = DateTime.Now.AddYears(-30).ToString("yyyy-MM-dd");
        Obj.Identity.AddressStreet = identity.Address.Street;
        Obj.Identity.AddressCity = identity.Address.City;
        Obj.Identity.AddressState = identity.Address.State;
        Obj.Identity.AddressZipCode = identity.Address.ZipCode;
        Obj.Identity.AddressCountry = identity.Address.Country;
        Obj.Identity.Hobbies = identity.Hobbies[0];
        Obj.Identity.EmailPrefix = identity.EmailPrefix;
        Obj.Identity.PhoneMobile = identity.PhoneMobile;
        Obj.Identity.BankAccountIBAN = identity.BankAccountIBAN;

        // Generate password
        GenerateRandomPassword();

        IsIdentityLoading = false;
        StateHasChanged();
    }

    private void GenerateRandomPassword()
    {
        // Generate a random password using a IPasswordGenerator implementation.
        IPasswordGenerator passwordGenerator = new SpamOkPasswordGenerator();
        Obj.Password.Value = passwordGenerator.GenerateRandomPassword();
    }

    private async Task SaveAlias()
    {
        IsSaving = true;
        StateHasChanged();

        // Try to extract favicon from service URL
        // TODO: Fix favicon extraction
        /*if (Obj.Service.Url != null  && !string.IsNullOrEmpty(Obj.Service.Url))
            {
            Obj.Service.Logo = await FaviconExtractor.FaviconService.GetFaviconAsync(Obj.Service.Url);
        } */

        // Sanity check for unittest. Delete later if not needed.
        // Try to parse birthdate as datetime. if it fails, set it to empty.
        if (Obj.Identity.BirthDate != null)
        {
            try
            {
                DateTime.Parse(Obj.Identity.BirthDate, new CultureInfo("en-US"));
            }
            catch (Exception)
            {
                Obj.Identity.BirthDate = "1900-01-01";
            }
        }

        if (EditMode)
        {
            if (Id is not null)
            {
                Id = await AliasService.UpdateAliasAsync(AliasEditToAlias(Obj), Id.Value);
            }
        }
        else
        {
            Id = await AliasService.InsertAliasAsync(AliasEditToAlias(Obj));
        }

        IsSaving = false;
        StateHasChanged();

        if (Id is null || Id == Guid.Empty)
        {
            // Error saving.
            GlobalNotificationService.AddErrorMessage("Error saving alias. Please try again.", true);
            return;
        }

        // No error, add success message.
        if (EditMode)
        {
            GlobalNotificationService.AddSuccessMessage("Alias updated successfully.");
        }
        else
        {
            GlobalNotificationService.AddSuccessMessage("Alias created successfully.");
        }

        Navigation.NavigateTo("/alias/" + Id);
    }

    private AliasEdit AliasToAliasEdit(Alias alias)
    {
        return new AliasEdit
        {
           ServiceName = alias.Service.Name,
           ServiceUrl = alias.Service.Url,
           Password = alias.Password,
           Identity = alias.Identity,
           CreateDate = alias.CreateDate,
           LastUpdate = alias.LastUpdate
        };
    }

    private Alias AliasEditToAlias(AliasEdit alias)
    {
        return new Alias
        {
            Service = new Service
            {
                Name = alias.ServiceName,
                Url = alias.ServiceUrl
            },
            Password = alias.Password,
            Identity = alias.Identity,
            CreateDate = alias.CreateDate,
            LastUpdate = alias.LastUpdate
        };
    }
}
