using JobTrackerApi.Services; namespace JobTrackerApi.Services.EmailProviders { /// /// Gmail implementation of . Adapts the existing /// (Gmail REST client) to the provider-neutral contract, /// mapping Gmail DTOs to the neutral shapes. /// public sealed class GmailProvider : IEmailProvider { private readonly IGmailOAuthService _gmail; public GmailProvider(IGmailOAuthService gmail) { _gmail = gmail; } public string ProviderKey => "gmail"; public async Task GetConnectionAsync(string ownerUserId, CancellationToken cancellationToken) { var connection = await _gmail.GetConnectionAsync(ownerUserId, cancellationToken); return connection is null ? null : new EmailConnectionInfo("gmail", connection.GmailAddress ?? ""); } public async Task> SearchAsync(string ownerUserId, string? query, int maxResults, CancellationToken cancellationToken) { var messages = await _gmail.ListMessagesAsync(ownerUserId, query, maxResults, cancellationToken); return messages.Select(ToSummary).ToList(); } public async Task> ListThreadMessagesAsync(string ownerUserId, string threadId, CancellationToken cancellationToken) { var messages = await _gmail.ListThreadMessagesAsync(ownerUserId, threadId, cancellationToken); return messages.Select(ToSummary).ToList(); } public async Task GetMessageAsync(string ownerUserId, string messageId, CancellationToken cancellationToken) { var detail = await _gmail.GetMessageAsync(ownerUserId, messageId, cancellationToken); var attachments = detail.Attachments .Select(a => new EmailAttachmentRef(a.FileName, a.MimeType, a.SizeBytes, a.GmailAttachmentId, a.Inline)) .ToList(); return new EmailMessageDetail( detail.Id, detail.ThreadId, detail.Subject, detail.From, detail.To, detail.Date, detail.Snippet, detail.BodyText, detail.BodyHtml, detail.Labels, attachments); } private static EmailMessageSummary ToSummary(GmailMessageSummary m) => new(m.Id, m.ThreadId, m.Subject, m.From, m.To, m.Date, m.Snippet); } }