namespace ZB.MOM.WW.ScadaBridge.NotificationService.Ews;

/// <summary>
/// One-shot EWS mail submission (<c>CreateItem</c>, <c>SendOnly</c>, BCC-only).
/// <para>
/// The seam the central Notification Outbox's <c>EmailNotificationDeliveryAdapter</c> calls when a
/// <c>SmtpConfiguration</c> selects the EWS transport, mirroring the role
/// <c>ISmtpClientWrapper</c> plays for the SMTP transport.
/// </para>
/// </summary>
public interface IEwsMailSender
{
    /// <summary>
    /// Sends one message through Exchange Web Services.
    /// </summary>
    /// <param name="request">The endpoint, credential, sender, recipients and content to submit.</param>
    /// <param name="cancellationToken">Token cancelling the send; propagates unwrapped when the caller cancels.</param>
    /// <returns>A task completing when Exchange has accepted the message.</returns>
    /// <exception cref="EwsPermanentException">
    /// The send failed for a reason retrying cannot fix — authentication (401/403), a wrong URL
    /// (404), a schema fault, or a recipient rejection.
    /// </exception>
    /// <exception cref="EwsTransientException">
    /// The send failed for an availability-shaped reason — network/DNS/timeout, HTTP 5xx/408/429,
    /// or an <c>ErrorServerBusy</c>-class response code — and is worth retrying.
    /// </exception>
    Task SendAsync(EwsSendRequest request, CancellationToken cancellationToken = default);
}

/// <summary>
/// Everything one EWS submission needs. Carried per call rather than held on the sender so the
/// sender stays a stateless singleton and the credential never outlives the request.
/// </summary>
/// <param name="Endpoint">The absolute HTTPS EWS URL (for example <c>https://host/EWS/Exchange.asmx</c>).</param>
/// <param name="Username">The service account, which may be domain-qualified (<c>domain\user</c>).</param>
/// <param name="Password">The service account password.</param>
/// <param name="FromAddress">The sending mailbox address.</param>
/// <param name="BccRecipients">The recipients; all addressed BCC so they cannot see one another.</param>
/// <param name="Subject">The message subject.</param>
/// <param name="Body">The plain-text message body.</param>
/// <param name="TimeoutSeconds">
/// The per-request timeout; a non-positive value leaves the <see cref="HttpClient"/> default in force.
/// </param>
public sealed record EwsSendRequest(
    Uri Endpoint,
    string Username,
    string Password,
    string FromAddress,
    IReadOnlyList<string> BccRecipients,
    string Subject,
    string Body,
    int TimeoutSeconds);

/// <summary>
/// Signals an availability-shaped EWS failure that is worth retrying.
/// </summary>
public class EwsTransientException : Exception
{
    /// <summary>
    /// Initializes the exception with a message and optional inner exception.
    /// </summary>
    /// <param name="message">Message describing the transient EWS failure; never carries the credential.</param>
    /// <param name="innerException">Optional underlying transport exception.</param>
    public EwsTransientException(string message, Exception? innerException = null)
        : base(message, innerException) { }
}

/// <summary>
/// Signals an EWS failure that retrying cannot fix, so the notification parks immediately.
/// </summary>
public class EwsPermanentException : Exception
{
    /// <summary>
    /// Initializes the exception with a message and optional inner exception.
    /// </summary>
    /// <param name="message">Message describing the permanent EWS failure; never carries the credential.</param>
    /// <param name="innerException">Optional underlying transport exception.</param>
    public EwsPermanentException(string message, Exception? innerException = null)
        : base(message, innerException) { }
}
