using GerbilManagerWebAPI.Models;
using MailKit.Security;

namespace GerbilManagerWebAPI.Inbox
{
    /// <summary>
    /// Sends a (human-edited) reply to a Request via SMTP, threaded into the original Gmail
    /// conversation, and marks the request Answered. Only ever called on the explicit
    /// POST /api/requests/{id}/send — never auto-sends.
    /// </summary>
    public sealed class SendReplyService
    {
        private readonly ApplicationContext _db;
        private readonly IGmailMailSender _sender;
        private readonly MailSettingsService _settings;

        public SendReplyService(ApplicationContext db, IGmailMailSender sender, MailSettingsService settings)
        {
            _db = db;
            _sender = sender;
            _settings = settings;
        }

        public async Task<SendOutcome> SendAsync(Request request, string body, CancellationToken ct = default)
        {
            var settings = await _settings.GetAsync(ct);
            var password = _settings.DecryptPassword(settings);
            if (string.IsNullOrWhiteSpace(settings.GmailAddress) || string.IsNullOrWhiteSpace(password))
                return SendOutcome.Fail("MailNotConfigured");

            var mail = new OutgoingMail(
                To: request.FromAddress,
                Subject: ReplySubject(request.Subject),
                Body: body,
                InReplyTo: request.GmailMessageId,
                References: BuildReferences(request.ReferencesHeader, request.GmailMessageId));

            try
            {
                await _sender.SendAsync(new MailConnection(settings.GmailAddress!, password!, settings.Folder), mail, ct);
            }
            catch (AuthenticationException)
            {
                return SendOutcome.Fail("MailAuthFailed");
            }

            request.Status = RequestStatus.Answered;
            request.AnsweredAt = DateTimeOffset.UtcNow;
            request.DraftReply = body;          // record what was actually sent
            await _db.SaveChangesAsync(ct);
            return SendOutcome.Ok;
        }

        /// <summary>"Re: " prefix without double-prefixing an existing reply subject.</summary>
        internal static string ReplySubject(string? original)
        {
            var s = (original ?? "").Trim();
            if (s.Length == 0) return "Re:";
            return s.StartsWith("Re:", StringComparison.OrdinalIgnoreCase) ? s : $"Re: {s}";
        }

        /// <summary>References = existing chain + the original Message-Id (deduped, in order).</summary>
        internal static string BuildReferences(string? existingChain, string originalMessageId)
        {
            var ids = (existingChain ?? "")
                .Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
                .ToList();
            if (!string.IsNullOrWhiteSpace(originalMessageId) && !ids.Contains(originalMessageId))
                ids.Add(originalMessageId);
            return string.Join(' ', ids);
        }
    }
}
