from email.message import EmailMessage as StdEmailMessage
from email.utils import formataddr
import logging

import aiosmtplib

from mode.email.base import EmailMessage, EmailProviderError


log = logging.getLogger("qycw.email.aliyunemail")


class AliyunEmailProvider:
    name = "aliyunemail"

    def __init__(self, settings):
        self.host = settings.SMTP_HOST
        self.port = settings.SMTP_PORT
        self.user = settings.SMTP_USER
        self.password = settings.SMTP_PASSWORD
        self.from_email = settings.SMTP_FROM_EMAIL
        self.from_name = settings.SMTP_FROM_NAME

    async def send(self, message: EmailMessage) -> None:
        self._ensure_configured()

        msg = StdEmailMessage()
        msg["From"] = formataddr((self.from_name, self.from_email))
        msg["To"] = message.to
        msg["Subject"] = message.subject
        msg.set_content(message.body, subtype=message.subtype, charset="utf-8")

        log.debug("sending email to=%s subject=%s smtp=%s:%s user=%s", message.to, message.subject, self.host, self.port, self.user)
        try:
            await aiosmtplib.send(
                msg,
                hostname=self.host,
                port=self.port,
                username=self.user,
                password=self.password,
                use_tls=True,
                timeout=15,
            )
        except Exception as exc:  # noqa: BLE001
            log.error("send email to %s failed: %s", message.to, exc)
            raise EmailProviderError("email send failed") from exc

        log.info("email sent to=%s subject=%s", message.to, message.subject)

    def _ensure_configured(self) -> None:
        missing = [
            name
            for name, value in {
                "SMTP_HOST": self.host,
                "SMTP_USER": self.user,
                "SMTP_PASSWORD": self.password,
                "SMTP_FROM_EMAIL": self.from_email,
            }.items()
            if not value
        ]
        if missing:
            raise EmailProviderError(f"email provider missing config: {', '.join(missing)}")


def create_provider(settings) -> AliyunEmailProvider:
    return AliyunEmailProvider(settings)

