using AsbCloudApp.Data;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services.Notifications;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Mail;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudInfrastructure.Services.Email
{

    public class EmailNotificationTransportService : INotificationTransportService
    {
        private readonly IUserRepository userRepository;
        private readonly string sender;
        private readonly string smtpPassword;
        private readonly string smtpServer;

        public int IdTransportType => 1;
        public bool IsConfigured { get; }

        public EmailNotificationTransportService(
            IConfiguration configuration,
            IUserRepository userRepository)
        {
            this.userRepository = userRepository;

            this.sender = configuration.GetValue("email:sender", string.Empty);
            this.smtpPassword = configuration.GetValue("email:password", string.Empty);
            this.smtpServer = configuration.GetValue("email:smtpServer", string.Empty);

            var configError = string.IsNullOrEmpty(this.sender) ||
                string.IsNullOrEmpty(this.smtpPassword) ||
                string.IsNullOrEmpty(this.smtpServer);

            this.IsConfigured = !configError;
        }

        public async Task SendAsync(NotificationDto notification, CancellationToken token)
        {
            if (!IsConfigured)
            {
                Trace.TraceWarning("smtp is not configured");
                return;
            }

            var user = await userRepository.GetOrDefaultAsync(notification.IdUser, token)
                           ?? throw new ArgumentInvalidException(nameof(notification.IdUser), "Пользователь не найден");

            if (!MailAddress.TryCreate(user.Email, out var mailAddress))
            {
                Trace.TraceWarning($"Mail {user.Email} is not correct.");
                throw new ArgumentInvalidException(nameof(user.Email), $"Mail {user.Email} is not null.");
            }

            var from = new MailAddress(sender);
            var message = new MailMessage
            {
                From = from
            };

            message.To.Add(mailAddress.Address);
            message.BodyEncoding = System.Text.Encoding.UTF8;
            message.Body = notification.Message;
            message.Subject = notification.Title;
            message.IsBodyHtml = true;

            using var client = new SmtpClient(smtpServer);
            client.EnableSsl = true;
            client.UseDefaultCredentials = false;
            client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword);

            await client.SendMailAsync(message, token);

            Trace.TraceInformation($"Send email to {user.Email} subj:{notification.Title} html body count {notification.Message.Length}");
        }

        public Task SendRangeAsync(IEnumerable<NotificationDto> notifications, CancellationToken cancellationToken)
        {
            var tasks = notifications
                .Select(notification => SendAsync(notification, cancellationToken));

            return Task.WhenAll(tasks);
        }
    }
}