@page "/sync"
@layout EmptyLayout
@implements IDisposable
@using AliasVault.Client.Main.Pages.Sync.StatusMessages
@inject ILocalStorageService LocalStorage
@inject DbService DbService
@inject AuthService AuthService
@inject NavigationManager NavigationManager
@inject ILogger<Sync> Logger

<LayoutPageTitle>Sync</LayoutPageTitle>

<div class="fixed inset-0 flex flex-col items-center justify-center px-6 pt-8 pb-8 h-full w-full">
    @if (CurrentDbState.Status == DbServiceState.DatabaseStatus.DecryptionFailed)
    {
        <ErrorVaultDecrypt />
    }
    else if (CurrentDbState.Status == DbServiceState.DatabaseStatus.PendingMigrations)
    {
        <PendingMigrations />
    }
    else if (CurrentDbState.Status == DbServiceState.DatabaseStatus.MergeFailed)
    {
        <ErrorVaultMerge message="@CurrentDbState.Message" />
    }
    else if (CurrentDbState.Status == DbServiceState.DatabaseStatus.MergeRequired)
    {
        <Merging />
    }
    else if (CurrentDbState.Status == DbServiceState.DatabaseStatus.Creating)
    {
        <Creating />
    }
    else
    {
        <VaultDecryptionProgress />
    }

    <div class="text-sm font-medium text-gray-500 dark:text-gray-400 mt-6">
        Switch accounts? <a href="/user/logout" class="text-primary-700 hover:underline dark:text-primary-500">Logout</a>
    </div>
</div>


@code {
    private const string ReturnUrlKey = "returnUrl";
    private DbServiceState.DatabaseState CurrentDbState { get; set; } = new();
    private const int MinimumLoadingTimeMs = 800;

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

        DbService.GetState().StateChanged += OnDatabaseStateChanged;
        CurrentDbState = DbService.GetState().CurrentState;

        // Check that encryption key is set. If not, redirect to unlock screen.
        if (!AuthService.IsEncryptionKeySet())
        {
            NavigationManager.NavigateTo("/unlock");
        }

        await CheckAndInitializeDatabase();
    }

    private async Task CheckAndInitializeDatabase()
    {
        CurrentDbState = DbService.GetState().CurrentState;
        if (CurrentDbState.Status == DbServiceState.DatabaseStatus.Uninitialized)
        {
            await InitializeDatabaseWithProgress();
        }
        else if (CurrentDbState.Status == DbServiceState.DatabaseStatus.Ready)
        {
            await RedirectBackToReturnUrl();
        }

        StateHasChanged();
    }

    private async void OnDatabaseStateChanged(object? sender, DbServiceState.DatabaseState newState)
    {
        CurrentDbState = DbService.GetState().CurrentState;
        if (CurrentDbState.Status == DbServiceState.DatabaseStatus.Uninitialized)
        {
            await InitializeDatabaseWithProgress();
        }
        else if (CurrentDbState.Status == DbServiceState.DatabaseStatus.Ready)
        {
            await RedirectBackToReturnUrl();
        }

        Logger.LogDebug("Database state changed: {NewStatus}", CurrentDbState.Status);
        StateHasChanged();
    }

    private async Task InitializeDatabaseWithProgress()
    {
        StateHasChanged();

        var stopwatch = System.Diagnostics.Stopwatch.StartNew();

        await DbService.InitializeDatabaseAsync();

        stopwatch.Stop();
        var elapsedMs = (int)stopwatch.ElapsedMilliseconds;

        if (elapsedMs < MinimumLoadingTimeMs)
        {
            await Task.Delay(MinimumLoadingTimeMs - elapsedMs);
        }

        await CheckAndInitializeDatabase();
        StateHasChanged();
    }

    private async Task RedirectBackToReturnUrl()
    {
        var localStorageReturnUrl = await LocalStorage.GetItemAsync<string>(ReturnUrlKey);
        var disallowedUrls = new[] { "/sync", "/unlock", "/user/logout" };

        if (!string.IsNullOrEmpty(localStorageReturnUrl) && !disallowedUrls.Contains(localStorageReturnUrl))
        {
            await LocalStorage.RemoveItemAsync(ReturnUrlKey);
            NavigationManager.NavigateTo(localStorageReturnUrl);
        }
        else
        {
            NavigationManager.NavigateTo("/");
        }
    }

    /// <inheritdoc />
    public void Dispose()
    {
        DbService.GetState().StateChanged -= OnDatabaseStateChanged;
    }
}
