using InboxIntel.Application.Common;
using InboxIntel.Application.DTOs;
using InboxIntel.Domain.Enums;
namespace InboxIntel.Application.Abstractions;
/// Orchestrates full + incremental Gmail sync, with resume support.
public interface ISyncService
{
Task RunFullSyncAsync(Guid userId, CancellationToken ct = default);
Task RunIncrementalSyncAsync(Guid userId, CancellationToken ct = default);
/// Marks the sync as starting and queues it for the background worker.
Task QueueSyncAsync(Guid userId, bool fullSync, CancellationToken ct = default);
Task GetStatusAsync(Guid userId, CancellationToken ct = default);
/// Progress snapshot for the sync splash screen.
Task GetProgressAsync(Guid userId, CancellationToken ct = default);
}
public interface IAnalyticsService
{
Task GetDashboardAsync(Guid userId, CancellationToken ct = default);
Task GetInboxHealthAsync(Guid userId, CancellationToken ct = default);
Task> GetTopSendersAsync(Guid userId, int take = 20, CancellationToken ct = default);
Task> GetVolumeOverTimeAsync(Guid userId, int days = 90, CancellationToken ct = default);
Task> GetHeatmapAsync(Guid userId, CancellationToken ct = default);
Task> GetCategoryHeatmapAsync(Guid userId, CancellationToken ct = default);
Task> GetAttachmentBreakdownAsync(Guid userId, CancellationToken ct = default);
Task GetSidebarCountsAsync(Guid userId, CancellationToken ct = default);
Task RefreshAggregatesAsync(Guid userId, CancellationToken ct = default);
}
public interface ISearchService
{
Task> SearchAsync(Guid userId, SearchRequestDto request, CancellationToken ct = default);
}
public interface ICleanupService
{
Task PreviewAsync(Guid userId, CleanupRequestDto request, CancellationToken ct = default);
Task> ExecuteAsync(Guid userId, CleanupRequestDto request, CancellationToken ct = default);
}
public interface IUnsubscribeService
{
Task> GetSafeToUnsubscribeAsync(Guid userId, CancellationToken ct = default);
Task DetectAsync(Guid userId, CancellationToken ct = default);
Task> ProcessQueueAsync(Guid userId, UnsubscribeRequestDto request, CancellationToken ct = default);
}
///
/// AI layer. May be disabled, local (Ollama) or cloud (OpenAI). Per the
/// safety rules, AI NEVER executes destructive actions - it only suggests.
///
public interface IAiService
{
bool IsEnabled { get; }
Task ClassifyAsync(Guid userId, Guid emailId, CancellationToken ct = default);
///
/// Lightweight classification used as a sync-time fallback when the
/// heuristic rule set doesn't match anything specific. Takes raw fields
/// directly (no DB lookup) since the email entity may not be persisted
/// yet during sync.
///
Task ClassifyFallbackAsync(string? subject, string senderAddress, string? snippet, CancellationToken ct = default);
///
/// AI opinion (0-1) on how safe it is to unsubscribe from a sender, given
/// the sender address and a recent subject line. Returns 0.5 (neutral) if
/// AI is disabled or the call fails - callers blend this with a heuristic.
///
Task ScoreUnsubscribeConfidenceAsync(string senderAddress, string? recentSubject, int emailCount, CancellationToken ct = default);
/// One-line plain-language summary of a single email, for list/preview UIs.
Task SummarizeEmailAsync(string? subject, string? snippet, string? bodyText, CancellationToken ct = default);
Task SummarizeInboxAsync(Guid userId, CancellationToken ct = default);
Task> SuggestCleanupAsync(Guid userId, CancellationToken ct = default);
Task GenerateQueryAsync(Guid userId, string naturalLanguage, CancellationToken ct = default);
}
/// Low-level chat completion abstraction implemented by Ollama / OpenAI providers.
public interface IAiProvider
{
AiProviderMode Mode { get; }
Task CompleteAsync(string systemPrompt, string userPrompt, CancellationToken ct = default);
}
///
/// Produces vector embeddings for text (the foundation for semantic search, near-duplicate
/// detection, and "find similar"). Kept separate from because
/// embeddings are a distinct capability with their own model. The Null implementation returns
/// an empty vector and = false, so callers detect unavailability and
/// fall back to lexical search — AI is never required for core functionality.
///
public interface IEmbeddingProvider
{
/// False for the Null provider (AI off / no embedding model configured).
bool IsAvailable { get; }
/// Embed a single text. Returns an empty array when unavailable.
Task EmbedAsync(string text, CancellationToken ct = default);
/// Embed many texts, result aligned to input order. Empty list when unavailable.
Task> EmbedBatchAsync(IReadOnlyList texts, CancellationToken ct = default);
}
public enum ExportFormat { Pdf, Csv, Json }
public interface IExportService
{
Task<(byte[] Content, string ContentType, string FileName)> ExportReportAsync(Guid userId, ExportFormat format, CancellationToken ct = default);
}
/// SMTP-backed email delivery, used for digest notifications. No-ops if SMTP is not configured.
public interface IEmailSender
{
bool IsEnabled { get; }
Task SendAsync(string toAddress, string subject, string htmlBody, CancellationToken ct = default);
}
/// Builds and sends the periodic inbox digest for opted-in users.
public interface IDigestService
{
Task SendDigestAsync(Guid userId, CancellationToken ct = default);
}