import mimetypes
import os
import smtplib
import utils
from email import encoders
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText


class EmailHelper:

    def __init__(self):
        self.smtp_server = utils.get_config_value("email.smtp_server")
        self.port = utils.get_config_value("email.smtp_port")
        self.username = utils.get_config_value("email.smtp_user")
        self.password = utils.get_config_value("email.smtp_password")
        self.from_email = utils.get_config_value("email.from_email")
        # print(
        #     f"server:{self.smtp_server},port:{self.port},username:{self.username},password:{self.password},from_email:{self.from_email}"
        # )

    def send_email(
        self,
        to_addr: str,
        subject: str,
        body: str,
        body_is_html: bool = True,
        attachment_paths: str = None,
    ):
        msg = MIMEMultipart()
        msg["From"] = self.from_email
        msg["To"] = ", ".join(to_addr.split(","))
        msg["Subject"] = subject

        # 根据 body_is_html 参数设置 MIMEText 类型
        if body_is_html:
            msg.attach(MIMEText(body, "html", "utf-8"))
        else:
            msg.attach(MIMEText(body, "plain", "utf-8"))

        if attachment_paths:
            attachment_arr = utils.to_array(attachment_paths)
            for attachment_path in attachment_arr:
                self._attach_file(msg, attachment_path)

        try:
            with smtplib.SMTP_SSL(
                self.smtp_server, port=self.port, timeout=10
            ) as server:
                # server.starttls()
                server.login(self.username, self.password)
                # 将 to_addr 字符串通过 split(',') 分割成列表，传递给 sendmail
                server.sendmail(self.from_email, to_addr.split(","), msg.as_string())
            utils.get_logger().info(f"邮件发送成功：{to_addr}")
            return True
        except smtplib.SMTPAuthenticationError:
            utils.get_logger().error("SMTP 认证失败")
        except smtplib.SMTPServerDisconnected:
            utils.get_logger().error("SMTP 服务器断开连接")
        except smtplib.SMTPException as e:
            utils.get_logger().error(f"SMTP 异常: {e}")
        except Exception as e:
            utils.get_logger().error(f"邮件发送失败：{to_addr} {e}")
            return False

    @staticmethod
    def _attach_file(msg: MIMEMultipart, attachment_path: str):
        if not os.path.isfile(attachment_path):
            utils.get_logger().error(f"文件 {attachment_path} 不存在。")
            return

        file_size = os.path.getsize(attachment_path)
        max_size = 1024 * 8192  # 8MB

        if file_size > max_size:
            utils.get_logger().error(
                f"文件 {attachment_path} 大小超过限制 ({file_size} bytes > {max_size} bytes)，不添加附件。"
            )
            return

        # 根据文件名后缀获取 MIME 类型
        content_type, _ = mimetypes.guess_type(attachment_path)
        if content_type is None:
            content_type = "application/octet-stream"  # 默认类型
        main_type, sub_type = content_type.split("/", 1)

        with open(attachment_path, "rb") as attachment:
            # part = MIMEBase('application', 'octet-stream')
            part = MIMEBase(main_type, sub_type)
            part.set_payload(attachment.read(max_size))
            # 获取文件名并去除第一个 @ 字符前面的部分
            name = os.path.basename(attachment_path)
            at_index = name.find("@")
            if at_index != -1:
                name = name[at_index + 1 :]

            # 使用 RFC 2047 编码文件名
            encoded_name = Header(name, "utf-8").encode()
            part.add_header(
                "Content-Disposition", f"attachment; filename= {encoded_name}"
            )
            # part.add_header("Content-ID", "<0>")
            # part.add_header("X-Attachment-Id", "0")
            encoders.encode_base64(part)
            msg.attach(part)
            utils.get_logger().info(f"添加附件 {name} {attachment_path} 到邮件中。")
