using System.Net.Http;
using NexusShell.Services;
using NexusShell.ViewModels;
using Xunit;

namespace NexusShell.Tests;

public sealed class LoginViewModelTests
{
    [Fact]
    public void Login_is_disabled_until_email_and_password_are_valid()
    {
        var vm = CreateViewModel((true, null));

        vm.Email = "user@nexus.local";
        vm.Password = string.Empty;
        Assert.False(vm.CanSubmit);
        Assert.False(vm.LoginCommand.CanExecute(null));

        vm.Password = "valid-input";
        Assert.True(vm.CanSubmit);
        Assert.True(vm.LoginCommand.CanExecute(null));
    }

    [Fact]
    public async Task Login_sets_loading_state_until_auth_returns()
    {
        var started = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var release = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        var vm = CreateViewModel(async (_, _) =>
        {
            started.SetResult();
            await release.Task;
            return (true, null);
        });
        vm.Password = "valid-input";

        vm.LoginCommand.Execute(null);
        await started.Task.WaitAsync(TimeSpan.FromSeconds(2));

        Assert.True(vm.IsBusy);
        Assert.Equal("Åbner session...", vm.LoginButtonLabel);
        Assert.False(vm.CanSubmit);

        release.SetResult();
        await WaitUntilAsync(() => !vm.IsBusy);
        Assert.True(vm.LoginSucceededState);
    }

    [Fact]
    public async Task Login_error_state_surfaces_failed_identity_response()
    {
        var vm = CreateViewModel((false, "Forkert email eller password"));
        vm.Password = "bad-password";

        vm.LoginCommand.Execute(null);
        await WaitUntilAsync(() => !vm.IsBusy && vm.HasError);

        Assert.True(vm.HasError);
        Assert.Equal("Forkert email eller password", vm.ErrorMessage);
        Assert.Equal("Login kræver opmærksomhed", vm.LoginStatusLabel);
    }

    [Fact]
    public async Task Login_success_raises_session_event()
    {
        var vm = CreateViewModel((true, null));
        var succeeded = false;
        vm.LoginSucceeded += (_, _) => succeeded = true;
        vm.Password = "valid-input";

        vm.LoginCommand.Execute(null);
        await WaitUntilAsync(() => succeeded);

        Assert.True(vm.LoginSucceededState);
        Assert.Equal("Session godkendt", vm.LoginStatusLabel);
    }

    private static LoginViewModel CreateViewModel((bool Success, string? Error) result) =>
        CreateViewModel((_, _) => Task.FromResult(result));

    private static LoginViewModel CreateViewModel(Func<string, string, Task<(bool Success, string? Error)>> loginHandler)
    {
        var auth = new AuthService(new HttpClient(), new ProfileService(), "http://localhost:5050", "test-client");
        return new LoginViewModel(auth, loginHandler);
    }

    private static async Task WaitUntilAsync(Func<bool> predicate)
    {
        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));
        while (!predicate())
        {
            await Task.Delay(10, cts.Token);
        }
    }
}
