using System;
using System.Linq;
using System.Threading.Tasks;
using ASHermed.SinoInterface.Api.ContractModel.SMTP;
using ASHermed.SinoInterface.IFramework.SMTP;
using ASHermed.SinoInterface.Tools;
using MailKit.Net.Smtp;
using Microsoft.Extensions.Logging;
using MimeKit;
using MimeKit.Text;

namespace ASHermed.SingleSignOnFramework.SMTP
{
    /// <summary>
    /// 邮件发送服务
    /// </summary>
    public class EmailService : IEmailService
    {
        private readonly ILogger<EmailService> _logger;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="logger"></param>
        public EmailService(ILogger<EmailService> logger)
        {
            _logger = logger;
        }


        /// <summary>
        /// 发送邮件
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<EmailSendOutput> SendAsync(EmailSendInput input)
        {
            var sendOutput = new EmailSendOutput();

            if (!input.To.Any())
            {
                sendOutput.IsSucceed = false;
                sendOutput.Description = "至少传入一个邮件接收人";

                return sendOutput;
            }

            try
            {
                var mimeMessage = BuildMimeMessage(input);

                using (var client = new SmtpClient())
                {
                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                    await client.ConnectAsync(EmailConfig.Host, 465, true);
                    await client.AuthenticateAsync(EmailConfig.SenderEmail, EmailConfig.AuthorizationCode);
                    await client.SendAsync(mimeMessage);
                    await client.DisconnectAsync(true);
                }

                sendOutput.IsSucceed = true;
                sendOutput.Description = "发送成功";

                _logger.LogInformation($"邮件发送成功：接收人-{input.To.ToJson()}；邮件标题-{input.Subject}；附件个数-{input.Attachments.Count}");
            }
            catch (Exception exception) when (exception.Message.Contains("authentication failed,error code[550 the password error] "))
            {
                var mimeMessage = BuildMimeMessage(input);
                //sino那边密码三个月会换一次，如果密码不对了，用另一个密码再试一下
                using (var client = new SmtpClient())
                {
                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                    await client.ConnectAsync(EmailConfig.Host, 465, true);
                    await client.AuthenticateAsync(EmailConfig.SenderEmail, EmailConfig.AuthorizationCode2);
                    await client.SendAsync(mimeMessage);
                    await client.DisconnectAsync(true);
                }

                sendOutput.IsSucceed = true;
                sendOutput.Description = "发送成功";

                _logger.LogInformation($"邮件发送成功：接收人-{input.To.ToJson()}；邮件标题-{input.Subject}；附件个数-{input.Attachments.Count}");
            }
            catch (Exception exception)
            {
                _logger.LogInformation($"邮件发送失败：发送内容{input.To.ToJson()}；错误信息：{exception.Message}");

                sendOutput.IsSucceed = false;
                sendOutput.Description = exception.Message;
            }

            return sendOutput;
        }

        /// <summary>
        /// 发送邮件（同步）
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public EmailSendOutput Send(EmailSendInput input)
        {
            var sendOutput = new EmailSendOutput();

            if (!input.To.Any())
            {
                sendOutput.IsSucceed = false;
                sendOutput.Description = "至少传入一个邮件接收人";

                return sendOutput;
            }

            try
            {
                var mimeMessage = BuildMimeMessage(input);

                using (var client = new SmtpClient())
                {
                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                    client.Connect(EmailConfig.Host, 465, true);
                    client.Authenticate(EmailConfig.SenderEmail, EmailConfig.AuthorizationCode);
                    client.Send(mimeMessage);
                    client.Disconnect(true);
                }

                sendOutput.IsSucceed = true;
                sendOutput.Description = "发送成功";

                _logger.LogInformation($"邮件发送成功：接收人-{input.To.ToJson()}；邮件标题-{input.Subject}；附件个数-{input.Attachments.Count}");
            }
            catch (Exception exception) when (exception.Message.Contains("authentication failed,error code[550 the password error] "))
            {
                var mimeMessage = BuildMimeMessage(input);

                //sino那边密码三个月会换一次，如果密码不对了，用另一个密码再试一下
                using (var client = new SmtpClient())
                {
                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                    client.Connect(EmailConfig.Host, 465, true);
                    client.Authenticate(EmailConfig.SenderEmail, EmailConfig.AuthorizationCode2);
                    client.Send(mimeMessage);
                    client.Disconnect(true);
                }

                sendOutput.IsSucceed = true;
                sendOutput.Description = "发送成功";

                _logger.LogInformation($"邮件发送成功：接收人-{input.To.ToJson()}；邮件标题-{input.Subject}；附件个数-{input.Attachments.Count}");
            }
            catch (Exception exception)
            {
                _logger.LogInformation($"邮件发送失败：发送内容{input.To.ToJson()}；错误信息：{exception.Message}");

                sendOutput.IsSucceed = false;
                sendOutput.Description = exception.Message;
            }

            return sendOutput;
        }

        private static MimeMessage BuildMimeMessage(EmailSendInput input)
        {
            var message = new MimeMessage();

            //添加发件人信息
            message.From.Add(new MailboxAddress(EmailConfig.SenderName, EmailConfig.SenderEmail));

            //添加收件人
            foreach (var to in input.To)
            {
                message.To.Add(new MailboxAddress(to, to));
            }

            message.Subject = input.Subject;

            var multipart = new Multipart("mixed");

            //添加html
            if (!string.IsNullOrEmpty(input.HtmlBody))
            {
                var html = new TextPart(TextFormat.Html)
                {
                    Text = input.HtmlBody
                };
                multipart.Add(html);
            }

            //添加文本
            if (!string.IsNullOrEmpty(input.TextBody))
            {
                var text = new TextPart(TextFormat.Text)
                {
                    Text = input.TextBody
                };
                multipart.Add(text);
            }

            //添加附件
            input.Attachments.Select(x => new MimePart
            {
                Content = new MimeContent(x.Value),
                ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),

                ContentTransferEncoding = ContentEncoding.Base64,

                FileName = x.Key
            })
                .ToList()
                .ForEach(multipart.Add);

            message.Body = multipart;

            return message;
        }
    }
}
