using CvMatcher.Models.Requests; using Api.Services.Contracts; using Microsoft.AspNetCore.Mvc; namespace Api.Controllers; [ApiController] [Route("api/cv")] public sealed class CvController : ControllerBase { private readonly ICvMatcherService _service; private readonly ILogger _logger; public CvController(ICvMatcherService service, ILogger logger) { _service = service; _logger = logger; } [HttpPost("upload")] [RequestSizeLimit(10 * 1024 * 1024)] public async Task Upload([FromForm(Name = "cv")] IFormFile? cv, [FromForm] bool gdprConsent, CancellationToken ct) { try { if (cv is null) return BadRequest(new { error = "Missing CV PDF." }); _logger.LogInformation("CV upload received. FileName={FileName}, Size={SizeBytes}, GdprConsent={GdprConsent}", cv.FileName, cv.Length, gdprConsent); var result = await _service.UploadCvAsync(cv, gdprConsent, ct); _logger.LogInformation("CV upload processed. CvDocumentId={CvDocumentId}, Cached={Cached}", result.DocumentId, result.Cached); return Ok(result); } catch (InvalidOperationException ex) { _logger.LogWarning(ex, "Invalid CV upload request."); return BadRequest(new { error = ex.Message }); } } [HttpPost("find-jobs")] public async Task FindJobs([FromBody] FindJobsRequest request, CancellationToken ct) { try { _logger.LogInformation("Find jobs request received. CvDocumentId={CvDocumentId}, TopK={TopK}", request.CvDocumentId, request.TopK); var result = await _service.FindJobsAsync(request, ct); _logger.LogInformation("Find jobs completed. CvDocumentId={CvDocumentId}, ResultCount={ResultCount}", request.CvDocumentId, result.Jobs.Count); return Ok(result); } catch (InvalidOperationException ex) { _logger.LogWarning(ex, "Invalid find jobs request."); return BadRequest(new { error = ex.Message }); } } [HttpPost("match-job")] public async Task MatchJob([FromBody] MatchJobRequest request, CancellationToken ct) { try { _logger.LogInformation("Match job request received. CvDocumentId={CvDocumentId}, HasJobUrl={HasJobUrl}, HasJobDescription={HasJobDescription}, EmailRequested={EmailRequested}", request.CvDocumentId, !string.IsNullOrWhiteSpace(request.JobUrl), !string.IsNullOrWhiteSpace(request.JobDescription), !string.IsNullOrWhiteSpace(request.Email)); var result = await _service.MatchJobAsync(request, ct); _logger.LogInformation("Match job completed. CvDocumentId={CvDocumentId}, Score={Score}, Cached={Cached}", request.CvDocumentId, result.Score, result.Cached); return Ok(result); } catch (InvalidOperationException ex) { _logger.LogWarning(ex, "Invalid match job request."); return BadRequest(new { error = ex.Message }); } } }