import ssl
from typing import Any

from django.conf import settings
from django.core.mail.backends.smtp import EmailBackend
from django.core.mail.utils import DNS_NAME


class VerifyTLSEmailBackend(EmailBackend):
    """
    Override the builtin backend to enforce
    SSL verification via setting. Don't need
    people sniffing password reset emails.
    """

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        super().__init__(*args, **kwargs)
        self.verify_tls = settings.EMAIL_VERIFY_TLS

    def open(self) -> bool | None:
        """
        Ensure an open connection to the email server. Return whether or not a
        new connection was required (True or False) or None if an exception
        passed silently.
        """
        # if not adding the custom verify_tls behavior, then use
        # superclass method to minimize chance of behavior changes
        if not self.use_tls or not self.verify_tls:
            return super().open()

        if self.connection:
            # Nothing to do if the connection is already open.
            return False

        # If local_hostname is not specified, socket.getfqdn() gets used.
        # For performance, we use the cached FQDN for local_hostname.
        connection_params = {'local_hostname': DNS_NAME.get_fqdn()}
        if self.timeout is not None:
            connection_params['timeout'] = self.timeout

        try:
            context = ssl.create_default_context()
            self.connection = self.connection_class(self.host, self.port, **connection_params)  # type: ignore[attr-defined]
            self.connection.starttls(context=context)  # type: ignore[union-attr]
            if self.username and self.password:
                self.connection.login(self.username, self.password)  # type: ignore[union-attr]
            return True
        except OSError:
            if not self.fail_silently:
                raise

        return False
