namespace Hims.Infrastructure.Helpers
{
    using System.Linq;
    using System.Threading.Tasks;
    using Domain.Configurations;
    using Domain.Helpers;
    using MailKit.Net.Smtp;
    using MailKit.Security;
    using MimeKit;
    using Shared.Library.MailKit;

    /// <inheritdoc />
    public class EmailHelper : IEmailHelper
    {
        /// <summary>
        /// The application configuration.
        /// </summary>
        private readonly IApplicationConfiguration applicationConfiguration;

        /// <summary>
        /// The email configuration.
        /// </summary>
        private readonly IEmailConfiguration emailConfiguration;

        /// <summary>
        /// The email configuration landing.
        /// </summary>
        private readonly IEmailConfigurationLanding emailConfigurationLanding;

        /// <summary>
        /// Initializes a new instance of the <see cref="EmailHelper"/> class.
        /// </summary>
        /// <param name="applicationConfiguration">
        /// The application Configuration.
        /// </param>
        /// <param name="emailConfiguration">
        /// The email configuration.
        /// </param>
        /// <param name="emailConfigurationLanding">
        /// The email configuration landing.
        /// </param>
        public EmailHelper(IApplicationConfiguration applicationConfiguration, IEmailConfiguration emailConfiguration, IEmailConfigurationLanding emailConfigurationLanding)
        {
            this.applicationConfiguration = applicationConfiguration;
            this.emailConfiguration = emailConfiguration;
            this.emailConfigurationLanding = emailConfigurationLanding;
        }

        /// <inheritdoc />
        public async Task SendAsync(EmailMessage emailMessage)
        {
            var priority = MessagePriority.Normal;
            if (emailMessage.Priority != null)
            {
                priority = (bool)emailMessage.Priority ? MessagePriority.Urgent : MessagePriority.NonUrgent;
            }

            var importance = MessageImportance.Normal;
            if (emailMessage.Importance != null)
            {
                importance = (bool)emailMessage.Importance ? MessageImportance.High : MessageImportance.Low;
            }

            var message = new MimeMessage();
            message.To.AddRange(emailMessage.ToAddresses.Select(x => new MailboxAddress(x.Name, !string.IsNullOrEmpty(this.applicationConfiguration.DefaultEmail) ? this.applicationConfiguration.DefaultEmail : x.Address)));
            message.Bcc.AddRange(emailMessage.BCCAddress.Select(x => new MailboxAddress(x.Name, x.Address)));
            message.Cc.AddRange(emailMessage.CCAddress.Select(x => new MailboxAddress(x.Name, x.Address)));
            message.Priority = priority;
            message.Importance = importance;
            message.Subject = emailMessage.Subject;
            message.Sender = new MailboxAddress(this.emailConfiguration.SenderName, this.emailConfiguration.FromName);

            var builder = new BodyBuilder { HtmlBody = emailMessage.Content };
            message.Body = builder.ToMessageBody();

            using (var emailClient = new SmtpClient())
            {
                await emailClient.ConnectAsync(this.emailConfiguration.Server, this.emailConfiguration.Port, SecureSocketOptions.Auto);
                emailClient.AuthenticationMechanisms.Remove("XOAUTH2");
                await emailClient.AuthenticateAsync(this.emailConfiguration.Username, this.emailConfiguration.Password);
                await emailClient.SendAsync(message);
                await emailClient.DisconnectAsync(true);
            }
        }

        /// <summary>
        /// The send email async.
        /// </summary>
        /// <param name="emailMessage">
        /// The email message.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public async Task SendEmailAsync(EmailMessage emailMessage)
        {
            var priority = MessagePriority.Normal;
            if (emailMessage.Priority != null)
            {
                priority = (bool)emailMessage.Priority ? MessagePriority.Urgent : MessagePriority.NonUrgent;
            }

            var importance = MessageImportance.Normal;
            if (emailMessage.Importance != null)
            {
                importance = (bool)emailMessage.Importance ? MessageImportance.High : MessageImportance.Low;
            }

            var message = new MimeMessage();
            message.To.AddRange(emailMessage.ToAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));
            message.Bcc.AddRange(emailMessage.BCCAddress.Select(x => new MailboxAddress(x.Name, x.Address)));
            message.Cc.AddRange(emailMessage.CCAddress.Select(x => new MailboxAddress(x.Name, x.Address)));
            message.Priority = priority;
            message.Importance = importance;
            message.Subject = emailMessage.Subject;
            message.Sender = new MailboxAddress(this.emailConfigurationLanding.SenderName, this.emailConfigurationLanding.FromName);

            var builder = new BodyBuilder { HtmlBody = emailMessage.Content };
            message.Body = builder.ToMessageBody();

            using (var emailClient = new SmtpClient())
            {
                await emailClient.ConnectAsync(this.emailConfigurationLanding.Server, this.emailConfigurationLanding.Port, SecureSocketOptions.Auto);
                emailClient.AuthenticationMechanisms.Remove("XOAUTH2");
                await emailClient.AuthenticateAsync(this.emailConfigurationLanding.Username, this.emailConfigurationLanding.Password);
                await emailClient.SendAsync(message);
                await emailClient.DisconnectAsync(true);
            }
        }
    }
}