using CvMatcher.Models.Responses; using CvSearch.Data.Entities; using EmailApi.Data.Services; using EmailApi.Models.Clients; using EmailApi.Models.Requests; using Microsoft.Extensions.Logging; namespace CvSearchJob.Services; public sealed class CvSearchEmailSender { private readonly IEmailApiClient _emailApi; private readonly IEmailTemplateService _emailTemplates; private readonly ILogger _logger; public CvSearchEmailSender( IEmailApiClient emailApi, IEmailTemplateService emailTemplates, ILogger logger) { _emailApi = emailApi; _emailTemplates = emailTemplates; _logger = logger; } public async Task SendResultsAsync( string toEmail, string? attachmentFileName, IReadOnlyList results, string language, CancellationToken ct) { var operatorCopy = _emailTemplates.GetOperatorCopy("email.search-results.subject", language); var recipients = new List(); if (!string.IsNullOrWhiteSpace(toEmail)) recipients.Add(toEmail); if (!string.IsNullOrWhiteSpace(operatorCopy) && !recipients.Any(r => string.Equals(r, operatorCopy, StringComparison.OrdinalIgnoreCase))) recipients.Add(operatorCopy); if (recipients.Count == 0) return; var htmlBody = BuildBody(results, language); var subject = _emailTemplates.Render("email.search-results.subject", language, ("count", results.Count.ToString())); try { await _emailApi.SendAsync(new SendEmailRequest { To = recipients, Subject = subject, HtmlBody = htmlBody, AttachmentPath = attachmentFileName }, ct); _logger.LogInformation("Job search results email sent to {Recipients}", string.Join(", ", recipients)); } catch (Exception ex) { _logger.LogError(ex, "Failed to send job search results email to {Recipients}", string.Join(", ", recipients)); } } private string BuildBody(IReadOnlyList results, string language) { if (results.Count == 0) return _emailTemplates.Get("email.search-results.empty", language); var items = new System.Text.StringBuilder(); for (int i = 0; i < results.Count; i++) { var r = results[i]; var matchResp = TryParseResult(r.ResultJson); var summary = matchResp?.Summary; items.Append($"""
{i + 1}. {r.JobTitle} {r.Score}% match [{r.ProviderName}]
{r.JobUrl} {(string.IsNullOrWhiteSpace(summary) ? "" : $"

{summary}

")}
"""); } return _emailTemplates.Render("email.search-results.body", language, ("count", results.Count.ToString()), ("items", items.ToString())); } private static JobMatchResponse? TryParseResult(string json) { try { return System.Text.Json.JsonSerializer.Deserialize(json, new System.Text.Json.JsonSerializerOptions(System.Text.Json.JsonSerializerDefaults.Web)); } catch { return null; } } }