using System.Data.Common;
using Dapr.Client;
using EntitlementBLL.Auth;
using EntitlementBLL.Legal;
using EntitlementBLL.Options;
using EntitlementDAL.DTOs;
using EntitlementDAL.Enums;
using EntitlementDAL.Interfaces;
using GB5Shared.DirectAction;
using GB5Shared.DTO.DirectAction;
using GB5Shared.ActionProcessor;
using GB5Shared.DTO.Framework.CommonConfig;
using GB5Shared.DTO.Framework.Login;
using GB5Shared.EventLogPublish;
using GB5Shared.GenerateAutoNumber;
using GB5Shared.QueryExecutor;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
namespace EntitlementTests;
///
/// Covers the Thread 8 capability-grant claim wiring: MENTITLEMENTCLIENTUSERROLE grants
/// (TECH_ADMIN/COMMERCIAL_ADMIN) are resolved once at login and carried on the JWT's Capabilities
/// claim, so an endpoint (e.g. RequestChangePlan) can check capability membership with no DB
/// round-trip. Covers both the claim serialization itself (ClientAccessTokenClaims.ToClaims) and
/// ClientAuthBLL.LoginAsync actually populating it from IClientUserRoleDAL.
///
public class ClientCapabilityTests
{
[Fact]
public void Test_ToClaims_WithCapabilities_ProducesCommaJoinedClaim()
{
var claims = new ClientAccessTokenClaims
{
ClientUserId = 1,
ClientId = 42,
Role = ClientRoleCodes.ClientAdmin,
Capabilities = new List { EntitlementClientCapabilityCodes.TechAdmin, EntitlementClientCapabilityCodes.CommercialAdmin }
};
var capabilitiesClaim = claims.ToClaims().Single(c => c.Type == ClientJwtClaimTypes.Capabilities);
Assert.Equal("TECH_ADMIN,COMMERCIAL_ADMIN", capabilitiesClaim.Value);
}
[Fact]
public void Test_ToClaims_NoCapabilities_ProducesEmptyClaim()
{
var claims = new ClientAccessTokenClaims { ClientUserId = 1, ClientId = 42, Role = ClientRoleCodes.ClientUser };
var capabilitiesClaim = claims.ToClaims().Single(c => c.Type == ClientJwtClaimTypes.Capabilities);
Assert.Equal(string.Empty, capabilitiesClaim.Value);
}
private static (ClientAuthBLL Svc, Mock ClientUserDal, Mock ClientUserRoleDal,
Mock JwtService) BuildService()
{
var clientUserDal = new Mock();
var clientUserRoleDal = new Mock();
var refreshTokenDal = new Mock();
var jwtService = new Mock();
jwtService.Setup(j => j.IssueTokenPairAsync(It.IsAny(), It.IsAny()))
.ReturnsAsync(new ClientTokenPair
{
AccessToken = "access-token", AccessTokenExpiresOn = DateTime.UtcNow.AddMinutes(15),
RefreshToken = "raw-refresh-token", RefreshTokenHash = "HASH-raw-refresh-token",
RefreshTokenExpiresOn = DateTime.UtcNow.AddDays(30)
});
clientUserDal.Setup(d => d.UpdateFailedLoginCountAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Returns(Task.CompletedTask);
clientUserDal.Setup(d => d.UpdateLastLoginOnAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Returns(Task.CompletedTask);
refreshTokenDal.Setup(d => d.SaveAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Returns(Task.CompletedTask);
var queryExecutor = new Mock();
queryExecutor
.Setup(q => q.QueryAsync(It.IsAny(), It.IsAny(), It.IsAny