using KiMailOrderAgent.Models;
using KiMailOrderAgent.Settings;
using MailKit;
using MailKit.Net.Imap;
using MailKit.Search;
using MimeKit;
using Microsoft.Extensions.Options;

namespace KiMailOrderAgent.Mail;

public class ImapMailReader : IMailReader
{
    private readonly MailSettings _settings;

    public ImapMailReader(IOptions<MailSettings> options)
    {
        _settings = options.Value;
    }

    public async Task<List<IncomingMail>> GetUnreadMailsAsync(CancellationToken cancellationToken)
    {
        var result = new List<IncomingMail>();

        using var client = new ImapClient();

        await client.ConnectAsync(
            _settings.ImapHost,
            _settings.ImapPort,
            true,
            cancellationToken);

        await client.AuthenticateAsync(
            _settings.Username,
            _settings.Password,
            cancellationToken);

        var inbox = client.Inbox;
        await inbox.OpenAsync(FolderAccess.ReadWrite, cancellationToken);

        var uids = await inbox.SearchAsync(SearchQuery.NotSeen, cancellationToken);

        foreach (var uid in uids)
        {
            var message = await inbox.GetMessageAsync(uid, cancellationToken);

            var mail = new IncomingMail
            {
                Id = uid.Id.ToString(),
                From = message.From.ToString(),
                Subject = message.Subject ?? "",
                Body = message.TextBody ?? message.HtmlBody ?? ""
            };

            foreach (var attachment in message.Attachments)
            {
                if (attachment is MimePart part)
                {
                    using var memoryStream = new MemoryStream();

                    await part.Content.DecodeToAsync(memoryStream, cancellationToken);

                    mail.Attachments.Add(new MailAttachment
                    {
                        FileName = part.FileName ?? "unknown",
                        ContentType = part.ContentType.MimeType,
                        Content = memoryStream.ToArray()
                    });
                }
            }

            result.Add(mail);

            await inbox.AddFlagsAsync(
                uid,
                MessageFlags.Seen,
                true,
                cancellationToken);
        }

        await client.DisconnectAsync(true, cancellationToken);

        return result;
    }
}