using MailKit;
using MailKit.Net.Imap;
using MailKit.Search;
using MailKit.Security;
using Microsoft.Extensions.Logging;
using MimeKit;
using PARR.Mail.Settings;

namespace PARR.Mail.Services
{
    internal class MailService : IMailService
    {
        private readonly ILogger<MailService> logger;
        private readonly MailSettings mailSettings;

        public MailService(ILogger<MailService> logger, MailSettings mailSettings)
        {
            this.logger = logger;
            this.mailSettings = mailSettings;
        }
        public async Task<IList<IMessageSummary>> CheckMailAsync(SearchQuery query)
        {
            using var client = await GetClient();

            IList<IMessageSummary> items = new List<IMessageSummary>();
            try
            {
                var uids = await client.Inbox.SearchAsync(query);
                items = await client.Inbox.FetchAsync(uids, MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure | MessageSummaryItems.Envelope);
            }
            catch (Exception e)
            {
                logger.LogError(e, "Ошибка получения списка писем");
            }
            return items;
        }

        public async Task<MimeEntity?> GetBodyPartAsync(IMessageSummary messageSummary)
        {
            try
            {
                using var client = await GetClient();

                return await client.Inbox.GetBodyPartAsync(messageSummary.UniqueId, messageSummary.TextBody);
            }
            catch (Exception e)
            {
                logger.LogError(e, "Ошибка получения тела письма");
            }
            return null;
        }

        public async Task<List<MimeEntity>> GetAttachmentsAsync(IMessageSummary messageSummary)
        {
            List<MimeEntity> result = new List<MimeEntity>();

            try
            {
                using var client = await GetClient();
                foreach (var attachment in messageSummary.Attachments)
                {
                    result.Add(await client.Inbox.GetBodyPartAsync(messageSummary.UniqueId, attachment));
                }
            }
            catch (Exception e)
            {
                logger.LogError(e, "Ошибка получения тела письма");
            }
            return result;
        }

        public async Task<string> GetBodyTextAsync(IMessageSummary messageSummary)
        {

            try
            {
                using var client = await GetClient();

                return ((TextPart)await client.Inbox.GetBodyPartAsync(messageSummary.UniqueId, messageSummary.TextBody)).Text;
            }
            catch (Exception e)
            {
                logger.LogError(e, "Ошибка содержания письма");
            }
            return string.Empty;
        }

        public async Task SetAsSeenAsync(IMessageSummary messageSummary)
        {
            try
            {
                using var client = await GetClient();

                await client.Inbox.AddFlagsAsync(messageSummary.UniqueId, MessageFlags.Seen, false);
            }
            catch (Exception e)
            {
                logger.LogError(e, "Не удалось сделать письмо прочитанным");
            }
        }

        private async Task<ImapClient> GetClient()
        {
            var client = new ImapClient();
            try
            {
                await client.ConnectAsync(mailSettings.Host, mailSettings.Port, SecureSocketOptions.None);
                await client.AuthenticateAsync(mailSettings.UserName, mailSettings.Password);
                await client.Inbox.OpenAsync(FolderAccess.ReadWrite);

                // игнорить сертификат
                client.CheckCertificateRevocation = false;
                client.ServerCertificateValidationCallback = (s, c, h, e) => true;
            } 
            catch(Exception e) {
                logger.LogError(e, "Не удалось создать почтовый клиент");
            }
            return client;
        }
    }
}
