using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using JdeScoping.Client.Services;
using JdeScoping.Core.Models.Auth;
using Microsoft.AspNetCore.Mvc.Testing;
namespace JdeScoping.Api.IntegrationTests.ClientIntegration;
///
/// Base class for API client integration tests.
/// Provides shared HttpClient with cookie handling for auth state.
///
[Collection("ClientIntegration")]
public abstract class ClientIntegrationTestBase : IClassFixture
{
protected readonly TestWebApplicationFactory Factory;
protected readonly HttpClient SharedClient;
// API clients share the authenticated HttpClient
protected readonly SearchApiClient SearchClient;
protected readonly LookupApiClient LookupClient;
protected readonly AuthApiClient AuthClient;
protected readonly FileApiClient FileClient;
protected ClientIntegrationTestBase(TestWebApplicationFactory factory)
{
Factory = factory;
SharedClient = factory.CreateClient(new WebApplicationFactoryClientOptions
{
HandleCookies = true,
AllowAutoRedirect = false
});
// All clients share the same HttpClient (cookie container)
SearchClient = new SearchApiClient(SharedClient);
LookupClient = new LookupApiClient(SharedClient);
FileClient = new FileApiClient(SharedClient);
AuthClient = new AuthApiClient(SharedClient);
}
///
/// Performs login with encrypted credentials.
///
protected async Task LoginAsync(string username = "testuser", string password = "testpass")
{
// Step 1: Get public key
var publicKeyResult = await AuthClient.GetPublicKeyAsync();
if (!publicKeyResult.IsSuccess)
throw new Exception("Failed to get public key");
// Step 2: Encrypt credentials
var loginModel = new LoginModel { Username = username, Password = password };
var json = JsonSerializer.Serialize(loginModel);
var plaintext = Encoding.UTF8.GetBytes(json);
using var rsa = RSA.Create();
rsa.ImportFromPem(publicKeyResult.Value.PublicKeyPem);
var ciphertext = rsa.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256);
// Step 3: Login
var encryptedRequest = new EncryptedLoginRequest(Convert.ToBase64String(ciphertext));
var loginResult = await AuthClient.LoginAsync(encryptedRequest);
if (!loginResult.IsSuccess || !loginResult.Value.Success)
throw new Exception($"Login failed: {loginResult.Value?.ErrorMessage ?? "Unknown error"}");
}
///
/// Creates a fresh HttpClient without cookies for testing unauthorized scenarios.
///
protected HttpClient CreateFreshClient() => Factory.CreateClient(new WebApplicationFactoryClientOptions
{
HandleCookies = false,
AllowAutoRedirect = false
});
}