using PostFundManagement.Domain.Abstractions; using PostFundManagement.Domain.Errors; using PostFundManagement.Domain.Models.Security; namespace PostFundManagement.Infrastructure.Security; public class SkorubaUserService([FromKeyedServices(SkorubaHttpClient)] IHttpClientFactory httpClientFactory) : ISkorubaUserService { public async Task> CreateUserAsync(CreateUserRequest request, Guid userId, CancellationToken cancellationToken = default) => await Result.Try((Func>>)(async () => { var httpClient = httpClientFactory.CreateClient(); var response = await httpClient.PostAsJsonAsync("api/users", request, cancellationToken); if (!response.IsSuccessStatusCode) return Result.Fail(CreateError.Create("Failed to create user.")); var created = await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken); return Result.FailIf(created is null, CreateError.Create("User ID missing from creation response.")) .ToResult(created?.Id!); })); public async Task> GetUserAsync(Guid userId, CancellationToken cancellationToken = default) => await Result.Try((Func>>)(async () => { var httpClient = httpClientFactory.CreateClient(); var result = await httpClient.GetFromJsonAsync($"api/users/{userId}", cancellationToken); return Result.FailIf(result is null, NotFoundError.Create($"User {userId} not found.")) .ToResult(result!); })); public async Task UpdateUserAsync(UpdateUserRequest request, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => { var httpClient = httpClientFactory.CreateClient(); var response = await httpClient.PutAsJsonAsync("api/users", request, cancellationToken); return Result.OkIf(response.IsSuccessStatusCode, UpdateError.Create("Failed to update user.")); })); public async Task SetUserLockoutAsync(Guid userId, bool disabled, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => { var httpClient = httpClientFactory.CreateClient(); var user = await httpClient.GetFromJsonAsync($"api/users/{userId}", cancellationToken); if (user is null) return Result.Fail(NotFoundError.Create($"User {userId} not found.")); var updated = user with { LockoutEnabled = true, LockoutEnd = disabled ? DateTimeOffset.UtcNow.AddYears(100) : null }; var response = await httpClient.PutAsJsonAsync("api/users", updated, cancellationToken); return Result.OkIf(response.IsSuccessStatusCode, UpdateError.Create("Failed to update user lockout status.")); })); public async Task AddClaimAsync(Guid userId, string claimType, string claimValue, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => { var httpClient = httpClientFactory.CreateClient(); var payload = new { UserId = userId, ClaimType = claimType, ClaimValue = claimValue }; var response = await httpClient.PostAsJsonAsync($"api/users/{userId}/claims", payload, cancellationToken); return Result.OkIf(response.IsSuccessStatusCode, CreateError.Create("Failed to add user claim.")); })); public async Task RemoveClaimAsync(Guid userId, int claimId, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => { var httpClient = httpClientFactory.CreateClient(); var response = await httpClient.DeleteAsync($"api/users/{userId}/claims/{claimId}", cancellationToken); return Result.OkIf(response.IsSuccessStatusCode, CreateError.Create("Failed to remove user claim.")); })); public async Task> GetUserClaimsAsync(Guid userId, int page = 1, int pageSize = 50, CancellationToken cancellationToken = default) => await Result.Try((Func>>)(async () => { var httpClient = httpClientFactory.CreateClient(); var result = await httpClient.GetFromJsonAsync($"api/users/{userId}/claims?page={page}&pageSize={pageSize}", cancellationToken); return Result.FailIf(result is null, NotFoundError.Create($"Claims for user {userId} could not be retrieved.")) .ToResult(result?.Claims.ToArray() ?? []); })); public async Task AddRoleAsync(Guid userId, string roleId, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => { var httpClient = httpClientFactory.CreateClient(); var payload = new { UserId = userId, RoleId = roleId }; var response = await httpClient.PostAsJsonAsync($"api/users/{userId}/roles", payload, cancellationToken); return Result.OkIf(response.IsSuccessStatusCode, CreateError.Create("Failed to add user role.")); })); public async Task RemoveRoleAsync(Guid userId, string roleId, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => { var httpClient = httpClientFactory.CreateClient(); var response = await httpClient.DeleteAsync($"api/users/{userId}/roles/{roleId}", cancellationToken); return Result.OkIf(response.IsSuccessStatusCode, CreateError.Create("Failed to remove user role.")); })); public async Task> GetUserRolesAsync(Guid userId, int page = 1, int pageSize = 50, CancellationToken cancellationToken = default) => await Result.Try((Func>>)(async () => { var httpClient = httpClientFactory.CreateClient(); var result = await httpClient.GetFromJsonAsync($"api/users/{userId}/roles?page={page}&pageSize={pageSize}", cancellationToken); return Result.FailIf(result is null, NotFoundError.Create($"Roles for user {userId} could not be retrieved.")) .ToResult(result?.Roles?.ToArray() ?? []); })); public async Task InvalidateUserSessionAsync(Guid userId, CancellationToken cancellationToken = default) => await Result.Try((Func>)(async () => { var httpClient = httpClientFactory.CreateClient(); var user = await httpClient.GetFromJsonAsync($"api/users/{userId}", cancellationToken); if (user is null) return Result.Fail(NotFoundError.Create($"User {userId} not found.")); var response = await httpClient.PutAsJsonAsync("api/users", user, cancellationToken); return Result.OkIf(response.IsSuccessStatusCode, UpdateError.Create("Failed to invalidate user session.")); })); public async Task> GetAvailableRolesAsync(string? searchText = null, int page = 1, int pageSize = 50, CancellationToken cancellationToken = default) => await Result.Try((Func>>)(async () => { var httpClient = httpClientFactory.CreateClient(); var query = $"api/roles?page={page}&pageSize={pageSize}"; if (!string.IsNullOrWhiteSpace(searchText)) query += $"&searchText={Uri.EscapeDataString(searchText)}"; var result = await httpClient.GetFromJsonAsync(query, cancellationToken); return Result.FailIf(result is null, NotFoundError.Create("Available roles could not be retrieved.")) .ToResult(result?.Roles?.ToArray() ?? []); })); }