using GB5Shared.Auth.Jwt;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
namespace RecruitmentBLL.Integration
{
/// Outcome of a DXP Party save call — same shape as DxpAuthOutcome. A failed sync
/// must propagate a real error back to AgencyBLL.SaveAgency (never silently no-op), because a
/// Recruitment Agency row with no valid DxpPartyId has no legal-identity backing at all.
public class DxpPartyOutcome
{
public bool Success { get; set; }
public string? Error { get; set; }
public int DxpPartyId { get; set; } = -1;
}
///
/// Cross-host HTTP integration with DXP's real Party surface (hosted by PlatformHost, a
/// different process than Recruitment's HRFinanceHost) — a thin wrapper over
/// POST /DXP/Party/SaveParty, following the exact IHttpClientFactory named-client pattern
/// established by RecruitmentBLL.Integration.DxpAuthIntegrationService/EcpIntegrationService.
///
/// Unlike DxpAuthIntegrationService's Register/Login (plain, unauthenticated FastEndpoints
/// Endpoint<,> — DXP resolves its own "system" LoginDTO internally), SaveParty is a
/// DXPBaseEndpoint<,> (see DXPSL/Common/DXPBaseEndpoint.cs's doc comment: "Endpoints do
/// not call AllowAnonymous(), so FastEndpoints' default auth requirement applies") — it
/// requires a valid DXP-signed Bearer JWT resolved into a DXPCallerContext via
/// HttpContext.User.Claims. Recruitment has no DXP user session to relay (this is a
/// system-to-system call triggered by a recruiter saving an Agency, not a logged-in DXP user
/// action), so this service mints its own short-lived DXP-signed token the exact same way
/// RecruitmentBLL.CandidatePortal.CandidatePortalBLL.LoginAsync already does for the opposite
/// direction (Recruitment issuing a token DXP/Recruitment both trust) — using DXP's own
/// signing key (Vault path "dxp/jwt-signing-key") and issuer/audience
/// ("DXPJwt:Issuer"/"DXPJwt:Audience", the same three values DXPSL/Program.cs's own
/// AddJwtBearer validates against), carrying only a "dxp_user_id" claim set to a system
/// sentinel (-1, matching DXPDAL.Common.DXPSystemContext.GetSystemLogin's own default). DXP's
/// SaveParty then resolves that into a system LoginDTO via
/// IDXPSystemContext.GetSystemLogin(caller.DxpUserId) — GetSystemLogin never looks the userId
/// up against MDXPUSER, so no real DXP user account is required for this call to succeed, only
/// a validly-signed token. Same precedent CandidatePortalBLL's own doc comment cites
/// (EntitlementSL's "PartnerM2MJwtBearer" scheme: one module issues using another's key, both
/// validate) — this is that pattern, reused for a system-to-system call instead of a
/// browser-held session token.
///
/// PartyTypeCode is caller-supplied (see AgencyBLL.DxpAgencyPartyTypeCode for why this module
/// maps a placement agency to PartyTypeCode=1/Vendor — DXP's PartyTypeCode enum has no
/// dedicated "Agency" value).
///
/// Degrades to a clear failure result (Success=false + Error) on a non-2xx response or thrown
/// exception — never throws back into AgencyBLL uncaught.
///
public interface IDxpPartyIntegrationService
{
/// dxpPartyId=0 creates a new DXP Party (DXP's own PartyBLL.SavePartyAsync
/// assigns the AutoNumber id and returns it); a nonzero value updates the existing Party's
/// LegalName in place. Mirrors DXP's own SaveParty semantics exactly (isNew := DxpPartyId
/// == 0).
Task SavePartyAsync(int dxpPartyId, string legalName, byte partyTypeCode, CancellationToken ct);
}
/// Claims embedded in the short-lived system token this service mints purely to call
/// DXP's own SaveParty endpoint — see IDxpPartyIntegrationService's doc comment. Deliberately
/// carries nothing but the one claim DXPCallerContext.FromClaims actually reads for this call
/// path (dxp_user_id); RoleCode/TenantId/etc are left at DXPCallerContext's own zero/empty
/// defaults, which is fine because DXPSystemContext.GetSystemLogin only ever reads the
/// DxpUserId it's passed.
public class DxpSystemAccessTokenClaims : IJwtClaimsSource
{
public int DxpUserId { get; set; } = -1;
public IEnumerable ToClaims() => new[]
{
new Claim("dxp_user_id", DxpUserId.ToString())
};
}
}