import logging
from email.message import EmailMessage

import aiosmtplib
from pydantic import BaseModel, ValidationError

from nyahome.config import config_manager
from nyahome.core.core_abc.task_queue import TaskQueue

logger = logging.getLogger(__name__)


class SendEmailItem(BaseModel):
    to: str
    subject: str
    body: str

    def __str__(self) -> str:
        return f"SendEmailItem(to={self.to}, subject={self.subject})"

    def __repr__(self) -> str:
        return self.__str__()


async def send_email(
    to: str,
    sender: str,
    subject: str,
    body: str,
    hostname: str,
    port: int,
    username: str,
    password: str,
    use_tls: bool,
) -> None:
    """
    底层的邮件发送方法，异步执行，调用 aiosmtplib.send()。不进行任何检查。

    Args:
        to: 收件人邮件地址
        sender: 发件人邮件地址
        subject: 邮件主题
        body: 邮件内容，可以是纯文本或者 HTML
        hostname: SMTP 服务器主机名
        port: SMTP 服务器端口
        username: SMTP 用户名，一般与发件人邮件地址相同
        password: SMTP 密码
        use_tls: 使用 TLS

    Raises:
        ValueError: 遭遇未知问题导致发件失败。
        aiosmtplib 的子异常类是可以排查的发件失败。
    """
    msg = EmailMessage()
    msg["From"] = sender
    msg["To"] = to
    msg["Subject"] = subject
    msg.set_content(body, subtype="html")

    try:
        res = await aiosmtplib.send(
            msg,
            hostname=hostname,
            port=port,
            username=username,
            password=password,
            use_tls=use_tls,
        )

        if len(res[0]) == 0:
            logger.debug(f"邮件发送成功 | {to=}, {subject=}")
        else:
            raise ValueError("邮件发送出现意外情况，我也不知道是什么情况……")
    except Exception as e:
        logger.error(f"邮件发送失败 | {e}")


class EmailSenderQueue(TaskQueue):
    """
    邮件发送任务队列。使用 put 方法提交的 item 需要为 :py:class:`SendEmailItem` 结构。
    """

    def __init__(self) -> None:
        super().__init__(2)

    async def _process(self, item: SendEmailItem) -> None:
        try:
            SendEmailItem.model_validate(item)
        except ValidationError as e:
            logger.error(f"向邮件发送队列提交了格式错误的 item - {e}")
            raise e
        await send_email(
            to=item.to,
            subject=item.subject,
            body=item.body,
            sender=config_manager.get("smtp_sender"),
            hostname=config_manager.get("smtp_hostname"),
            port=config_manager.get("smtp_port"),
            username=config_manager.get("smtp_username"),
            password=config_manager.get("smtp_password"),
            use_tls=config_manager.get("smtp_use_tls"),
        )


email_sender_queue = EmailSenderQueue()
