"""Outgoing mail.

Everything that sends email goes through `notify` or `send_now` here, so the
settings in /admin/settings/?tab=email are the single place that decides how
mail leaves the system — and whether it leaves at all.
"""

import os

from django.core.mail import EmailMessage, get_connection

from .models import EmailSettings


def build_connection(settings_row=None, fail_silently=False):
    """Open a connection using whatever the panel is configured for.

    Falls back to the environment variables in .env when the panel has no
    host set, and to the console when there is nothing configured anywhere.
    """
    row = settings_row or EmailSettings.load()

    if row.provider == EmailSettings.CONSOLE or not row.enabled:
        return get_connection("django.core.mail.backends.console.EmailBackend",
                              fail_silently=fail_silently)

    host = row.host or os.getenv("EMAIL_HOST", "")
    if not host:
        return get_connection("django.core.mail.backends.console.EmailBackend",
                              fail_silently=fail_silently)

    password = row.password or os.getenv("EMAIL_HOST_PASSWORD", "")
    return get_connection(
        "django.core.mail.backends.smtp.EmailBackend",
        host=host,
        port=row.port or int(os.getenv("EMAIL_PORT", "587")),
        username=row.username or os.getenv("EMAIL_HOST_USER", ""),
        password=password,
        use_tls=row.use_tls,
        use_ssl=row.use_ssl,
        timeout=20,
        fail_silently=fail_silently,
    )


def send_now(subject, body, to, reply_to=None, fail_silently=True):
    """Send one message, ignoring the per-event switches. Used by the test button."""
    row = EmailSettings.load()
    recipients = [to] if isinstance(to, str) else list(to)
    recipients = [r for r in recipients if r]
    if not recipients:
        return 0

    message = EmailMessage(
        subject=subject,
        body=body,
        from_email=row.sender,
        to=recipients,
        reply_to=[reply_to or row.reply_to] if (reply_to or row.reply_to) else None,
        connection=build_connection(row, fail_silently=fail_silently),
    )
    return message.send(fail_silently=fail_silently)


def notify(event, subject, body, to, client=None, reply_to=None):
    """Send mail for a named event, honouring both switches.

    `event` matches the `on_*` fields on EmailSettings — the owner's switches.
    `client` is the recipient when the mail goes to a client, so their own
    notification preferences are respected too.
    """
    row = EmailSettings.load()
    if not row.enabled and row.provider != EmailSettings.CONSOLE:
        return 0
    if not row.event_allowed(event):
        return 0
    if client is not None and not client_wants(client, event):
        return 0
    return send_now(subject, body, to, reply_to=reply_to)


# Which client checkbox governs which event.
CLIENT_PREFERENCE = {
    "project_status": "notify_project_updates",
    "invoice_issued": "notify_invoices",
    "payment_received": "notify_payments",
    "new_message": "notify_messages",
    "ticket_reply": "notify_tickets",
    "ticket_opened": "notify_tickets",
    "renewal": "notify_renewals",
}


def client_wants(client, event):
    field = CLIENT_PREFERENCE.get(event)
    if field is None:
        return True
    return bool(getattr(client, field, True))
