using AsbCloudApp.Data;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services.Notifications;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.Configuration;
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<string>("email:sender")
            ?? throw new ConfigurationErrorsException("email:sender не определен");

        this.smtpPassword = configuration.GetValue<string>("email:password")
            ?? throw new ConfigurationErrorsException("email:password не определен");

        this.smtpServer = configuration.GetValue<string>("email:smtpServer")
            ?? throw new ConfigurationErrorsException("email:smtpServer не определен");

        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);
    }
}