using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using GB5Shared.Auth.Jwt;
using GB5Shared.DTO.ECM;
using GB5Shared.DTO.Framework.Login;
namespace RecruitmentBLL.CandidatePortal
{
///
/// Claim type names for the CandidatePortal access token — read on the RecruitmentSL side by
/// CandidatePortalCallerContext.FromClaims after the "CandidatePortal" JwtBearer scheme has
/// verified the token's signature (see RecruitmentSL/Program.cs).
///
public static class CandidatePortalClaimTypes
{
public const string DxpUserId = "dxp_user_id";
public const string CandidateId = "candidate_id";
public const string Email = "email";
}
///
/// Claims embedded in every CandidatePortal access token, minted by
/// CandidatePortalBLL.LoginAsync — see that class's doc comment for why Recruitment mints
/// this token itself (using DXP's own signing key/issuer/audience) instead of relaying DXP's
/// raw Login-issued token verbatim.
///
public class CandidatePortalAccessTokenClaims : IJwtClaimsSource
{
public int DxpUserId { get; set; }
public int CandidateId { get; set; }
public string Email { get; set; } = string.Empty;
public IEnumerable ToClaims() => new[]
{
new Claim(CandidatePortalClaimTypes.DxpUserId, DxpUserId.ToString()),
new Claim(CandidatePortalClaimTypes.CandidateId, CandidateId.ToString()),
new Claim(CandidatePortalClaimTypes.Email, Email)
};
}
public class CandidatePortalLoginResultDTO
{
public bool Success { get; set; }
public string? Error { get; set; }
public int CandidateId { get; set; } = -1;
public string Email { get; set; } = string.Empty;
public string AccessToken { get; set; } = string.Empty;
public DateTime AccessTokenExpiresOn { get; set; }
}
public interface ICandidatePortalBLL
{
/// Thin passthrough to DXP's real /DXP/Auth/Register, then eagerly ensures a
/// matching MCANDIDATE row exists for this email (see EnsureCandidateAsync) so a first
/// Login right after registering never has to create one mid-request.
Task RegisterAsync(string fullName, string email, string? mobile, string password, LoginDTO login, CancellationToken ct);
/// Validates credentials against DXP, resolves/creates the matching
/// MCANDIDATE.CandidateId by email, and mints a CandidatePortal access token carrying it.
/// Success=false (never an exception) on bad credentials — callers must return a real
/// 401, not a silent no-op.
Task LoginAsync(string email, string password, LoginDTO login, CancellationToken ct);
Task GetMyApplicationsAsync(int candidateId, LoginDTO login, CancellationToken ct);
Task UploadDocumentAsync(
int candidateId, Stream fileStream, string fileName, string contentType,
string? remarks, LoginDTO login, CancellationToken ct);
}
}