using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;

namespace ScadaLink.NotificationService;

/// <summary>
/// WP-11: MailKit-based SMTP client wrapper.
/// Supports OAuth2 Client Credentials (M365) and Basic Auth.
/// BCC delivery, plain text.
/// </summary>
public class MailKitSmtpClientWrapper : ISmtpClientWrapper, IDisposable
{
    private readonly SmtpClient _client = new();

    public async Task ConnectAsync(
        string host,
        int port,
        SmtpTlsMode tlsMode,
        int connectionTimeoutSeconds,
        CancellationToken cancellationToken = default)
    {
        // NS-005: map the explicit three-state TLS mode onto MailKit's socket
        // options. The old code collapsed everything to a boolean and used
        // SecureSocketOptions.Auto for the non-StartTLS case, which let MailKit
        // opportunistically negotiate TLS even when "None" was configured and
        // gave SSL-on-connect no representation at all.
        var secureSocket = tlsMode switch
        {
            SmtpTlsMode.None => SecureSocketOptions.None,
            SmtpTlsMode.StartTls => SecureSocketOptions.StartTls,
            SmtpTlsMode.Ssl => SecureSocketOptions.SslOnConnect,
            _ => throw new ArgumentOutOfRangeException(nameof(tlsMode), tlsMode, "Unknown TLS mode."),
        };

        // NS-007: honour the configured connection timeout. SmtpClient.Timeout is
        // in milliseconds and applies to connect/auth/send operations.
        if (connectionTimeoutSeconds > 0)
        {
            _client.Timeout = connectionTimeoutSeconds * 1000;
        }

        await _client.ConnectAsync(host, port, secureSocket, cancellationToken);
    }

    public async Task AuthenticateAsync(string authType, string? credentials, CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrEmpty(credentials))
            return;

        switch (authType.ToLowerInvariant())
        {
            case "basic":
                var parts = credentials.Split(':', 2);
                if (parts.Length == 2)
                {
                    await _client.AuthenticateAsync(parts[0], parts[1], cancellationToken);
                }
                break;

            case "oauth2":
                // OAuth2 token is passed directly as credentials (pre-fetched by token service)
                var oauth2 = new SaslMechanismOAuth2("", credentials);
                await _client.AuthenticateAsync(oauth2, cancellationToken);
                break;
        }
    }

    public async Task SendAsync(string from, IEnumerable<string> bccRecipients, string subject, string body, CancellationToken cancellationToken = default)
    {
        var message = new MimeMessage();
        message.From.Add(MailboxAddress.Parse(from));

        foreach (var recipient in bccRecipients)
        {
            message.Bcc.Add(MailboxAddress.Parse(recipient));
        }

        message.Subject = subject;
        message.Body = new TextPart("plain") { Text = body };

        await _client.SendAsync(message, cancellationToken);
    }

    public async Task DisconnectAsync(CancellationToken cancellationToken = default)
    {
        if (_client.IsConnected)
        {
            await _client.DisconnectAsync(true, cancellationToken);
        }
    }

    public void Dispose()
    {
        _client.Dispose();
    }
}
