using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MimeKit;
using OmsorgCore.Application.Abstractions;

namespace OmsorgCore.Email;

/// <summary>
/// Echter Mail-Versand über SMTP (MailKit statt des veralteten System.Net.Mail.SmtpClient).
/// Ein gemeinsamer Server (<see cref="EmailOptions.Smtp"/>), Login/Absender kommen aus dem per
/// <see cref="EmailMessage.FromAccountKey"/> gewählten Account (<see cref="EmailOptions.Accounts"/>) -
/// alles aus appsettings/Env-Var/user-secrets, nie vom Client.
/// </summary>
public class SmtpEmailSender : IEmailSender
{
    private readonly EmailOptions _options;
    private readonly ILogger<SmtpEmailSender> _logger;

    public SmtpEmailSender(IOptions<EmailOptions> options, ILogger<SmtpEmailSender> logger)
    {
        _options = options.Value;
        _logger = logger;
    }

    public async Task SendAsync(EmailMessage message, CancellationToken cancellationToken = default)
    {
        var accountKey = message.FromAccountKey ?? _options.PasswordResetAccount;
        if (!_options.Accounts.TryGetValue(accountKey, out var account))
        {
            throw new InvalidOperationException(
                $"Kein E-Mail-Account mit Schlüssel '{accountKey}' unter Email:Accounts konfiguriert.");
        }

        var mimeMessage = new MimeMessage();
        mimeMessage.From.Add(new MailboxAddress(account.SenderDisplayName, account.SenderAddress));
        mimeMessage.To.Add(MailboxAddress.Parse(message.ToAddress));
        mimeMessage.Subject = message.Subject;
        mimeMessage.Body = new TextPart("plain") { Text = message.PlainTextBody };

        var smtp = _options.Smtp;

        using var client = new SmtpClient();
        await client.ConnectAsync(
            smtp.Host,
            smtp.Port,
            smtp.EnableSsl ? SecureSocketOptions.StartTlsWhenAvailable : SecureSocketOptions.None,
            cancellationToken);
        await client.AuthenticateAsync(account.Username, account.Password, cancellationToken);
        await client.SendAsync(mimeMessage, cancellationToken);
        await client.DisconnectAsync(true, cancellationToken);

        _logger.LogInformation("[SmtpEmailSender] Mail an {To} über {Host}:{Port} (Account {Account}) versendet.",
            message.ToAddress, smtp.Host, smtp.Port, accountKey);
    }
}
