using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using Baya.Application.Contracts.Identity;
using Baya.Domain.Entities.User;
using Microsoft.Extensions.DependencyInjection;

namespace Baya.Test.Api;

/// <summary>
/// Shared plumbing for the auth flows: creates users + valid OTP codes through the real Identity
/// services (so tests don't scrape logs or burn the OTP endpoint's rate-limit budget on setup), and
/// unwraps the ApiResult envelope.
/// </summary>
internal static class AuthTestClient
{
    public static async Task<string> CreateUserWithOtpCodeAsync(BayaApiFactory factory, string phone)
    {
        using var scope = factory.Services.CreateScope();
        var userManager = scope.ServiceProvider.GetRequiredService<IAppUserManager>();

        var user = await userManager.GetUserByPhoneNumber(phone);
        if (user is null)
        {
            user = new User { UserName = $"u_{Guid.NewGuid():N}", PhoneNumber = phone };
            var created = await userManager.CreateUser(user);
            Assert.True(created.Succeeded, $"test user creation failed: {string.Join(",", created.Errors.Select(e => e.Description))}");
        }

        // Same token family the verify endpoint checks: phone-confirmation token before the phone is
        // confirmed, passwordless TOTP afterwards.
        return user.PhoneNumberConfirmed
            ? await userManager.GenerateOtpCode(user)
            : await userManager.GeneratePhoneNumberConfirmationToken(user, phone);
    }

    /// <summary>Full endpoint login: mints a code, POSTs verify_otp, returns the token payload.</summary>
    public static async Task<JsonElement> LoginAsync(BayaApiFactory factory, HttpClient client, string phone)
    {
        var code = await CreateUserWithOtpCodeAsync(factory, phone);

        var response = await client.PostAsJsonAsync("/api/v1/auth/verify_otp", new { phone, code });
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);

        return await ReadDataAsync(response);
    }

    public static void UseBearer(HttpClient client, string accessToken) =>
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

    /// <summary>Unwraps the ApiResult envelope and returns its <c>data</c> element.</summary>
    public static async Task<JsonElement> ReadDataAsync(HttpResponseMessage response)
    {
        var json = await response.Content.ReadAsStringAsync();
        using var document = JsonDocument.Parse(json);
        return document.RootElement.GetProperty("data").Clone();
    }
}