using Microsoft.AspNetCore.Components;

namespace Guestlist.Components.Pages;

public partial class Setup : ComponentBase
{
    [Inject]
    protected SetupStatusService SetupStatusService { get; set; } = default!;

    [Inject]
    protected UserService UserService { get; set; } = default!;
    
    [Inject]
    protected AccessCodeService AccessCodeService { get; set; } = default!;

    [Inject]
    protected GuestEntryService GuestEntryService { get; set; } = default!;

    [Inject]
    protected DatabaseBackupService DatabaseBackupService { get; set; } = default!;
    
    protected string Username { get; set; } = "";
    protected string DisplayName { get; set; } = "";
    protected string Password { get; set; } = "";
    protected string ErrorMessage { get; set; } = "";
    
    protected bool? HasAnyUsers { get; set; }
    protected bool? HasAnyDatabaseBackups { get; set; }
    
    protected string GuestAccessCode { get; set; } = "";
    
    protected bool? IsSetupComplete { get; set; }

    [SupplyParameterFromQuery(Name = "error")]
    public string? SetupError { get; set; }

    [SupplyParameterFromQuery(Name = "backupDatabase")]
    public string? BackupDatabase { get; set; }

    [SupplyParameterFromQuery(Name = "backedUpCollections")]
    public int? BackedUpCollections { get; set; }

    [SupplyParameterFromQuery(Name = "backedUpDocuments")]
    public long? BackedUpDocuments { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (!string.IsNullOrWhiteSpace(SetupError))
        {
            ErrorMessage = SetupError switch
            {
                "existing-user" => "Setup cannot create another initial admin user.",
                "setup-failed" => "Setup could not be completed. No partial admin user was kept.",
                "setup-reset" => $"Setup has been reset. The old database was copied to {BackupDatabase ?? "a backup database"}. {BackedUpCollections ?? 0} collections and {BackedUpDocuments ?? 0} documents were backed up.",
                "restore-users-exist" => "Cannot restore backup while users already exist.",
                "restore-failed" => "Could not restore latest database backup.",
                _ => SetupError
            };
        }

        try
        {
            IsSetupComplete = await SetupStatusService.IsSetupCompleteAsync();
            HasAnyUsers = await UserService.HasAnyUsersAsync();
            HasAnyDatabaseBackups = await DatabaseBackupService.HasAnyDatabaseBackupsAsync();
        }
        catch
        {
            ErrorMessage = "Setup status could not be loaded. Please try again.";
            IsSetupComplete = false;
            HasAnyUsers = false;
            HasAnyDatabaseBackups = false;
        }
    }
    
    protected async Task CompleteSetup()
    {
        ErrorMessage = "";

        if (await UserService.HasAnyUsersAsync())
        {
            ErrorMessage = "Setup cannot create another initial admin user!";
            return;
        }

        if (string.IsNullOrWhiteSpace(Username))
        {
            ErrorMessage = "Provide a username.";
            return;
        }
        
        if (string.IsNullOrWhiteSpace(DisplayName))
        {
            DisplayName = Username;
        }

        if (string.IsNullOrWhiteSpace(Password))
        {
            ErrorMessage = "Provide a password.";
            return;
        }

        if (Password.Length < 8)
        {
            ErrorMessage = "Password must be at least 8 characters long.";
            return;
        }
        
        if (string.IsNullOrWhiteSpace(GuestAccessCode))
        {
            ErrorMessage = "Provide a guest access code.";
            return;
        }

        var adminCreated = false;

        try
        {
            await UserService.CreateAdminAsync(DisplayName, Username, Password);
            adminCreated = true;

            await AccessCodeService.SetGuestAccessCodeAsync(GuestAccessCode);
            await SetupStatusService.MarkSetupCompleteAsync();
        }
        catch (InvalidOperationException exception)
        {
            ErrorMessage = exception.Message;
            return;
        }
        catch
        {
            if (adminCreated)
            {
                await UserService.DeleteUserByUsernameAsync(Username);
            }

            HasAnyUsers = await UserService.HasAnyUsersAsync();
            ErrorMessage = "Setup could not be completed. No partial admin user was kept.";
            return;
        }

        GuestAccessCode = "";
        Password = "";
        HasAnyUsers = true;
        IsSetupComplete = true;
    }
    
    protected async Task RestoreLatestBackup()
    {
        ErrorMessage = "";

        if (HasAnyUsers == true)
        {
            ErrorMessage = "Cannot restore backup while users already exist.";
            return;
        }

        if (HasAnyDatabaseBackups != true)
        {
            ErrorMessage = "No database backups found.";
            return;
        }

        DatabaseBackupResult? restored;

        try
        {
            restored = await DatabaseBackupService.RestoreLatestDatabaseBackupAsync();
        }
        catch
        {
            ErrorMessage = "Could not restore latest database backup.";
            return;
        }

        if (restored is null)
        {
            ErrorMessage = "Could not restore latest database backup.";
            return;
        }

        try
        {
            await SetupStatusService.MarkSetupCompleteAsync();
            await UserService.EnsureIndexesAsync();
            await GuestEntryService.EnsureIndexesAsync();
            await AccessCodeService.EnsureIndexesAsync();
        }
        catch
        {
            ErrorMessage = "Backup was restored, but setup status could not be updated.";
            return;
        }
        
        HasAnyUsers = true;
        IsSetupComplete = true;
        HasAnyDatabaseBackups = await DatabaseBackupService.HasAnyDatabaseBackupsAsync();
        
        ErrorMessage = "Latest database backup has been restored.";
    }
}
