#!/usr/bin/env python
"""
@Project ：django_base_ai
@File    ：smtp_email.py
@Author  ：congxing.wang
@Date    ：2026/02/25
@Desc    ：SMTP 邮件发送
"""

import logging
import os
import smtplib
import sys
from email.header import Header
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formataddr
from pathlib import Path

import django
from jinja2 import Template

from django_base_ai import dispatch

# 获取日志记录器
logger = logging.getLogger(__name__)


class SmtpEmail:
    def __init__(self):

        # SMTP开启SSL，如果配置为None则默认为True（QQ邮箱需要SSL）
        self.smtp_ssl = dispatch.get_system_config_values("message.smtp_ssl")
        if self.smtp_ssl is None:
            self.smtp_ssl = True
        # SMTP服务器IP
        self.email_host = dispatch.get_system_config_values("message.smtp_email_host")
        # SMTP服务器端口
        self.host_port = dispatch.get_system_config_values("message.smtp_email_host_port")
        # SMTP邮箱发件人名称
        self.email_name = dispatch.get_system_config_values("message.smtp_email_name")
        # SMTP邮箱发件人
        self.email_address = dispatch.get_system_config_values("message.smtp_email_address")
        # SMTP邮箱密码
        self.password = dispatch.get_system_config_values("message.smtp_email_password")
        self.check = False
        if self.email_host or self.host_port or self.email_address:
            self.check = True
            logger.info(
                f"SMTP开启SSL={self.smtp_ssl},SMTP服务器IP={self.email_host}, 端口={self.host_port}, 发件人账号={self.email_address},请检查配置-系统配置-系统通知设置项"
            )

    def send(
        self,
        to_mail,
        subject,
        content,
        cc_list=None,
        bcc_list=None,
        file_list=None,
        content_kwargs={},
        new_formataddr=(),
    ):
        """
        发送邮件，支持抄送、密送和附件
        Args:
            to_mail: 收件人邮箱地址，可以是字符串或列表
            subject: 邮件主题
            content: 邮件内容（HTML格式）
            cc_list: 抄送人列表，默认为None
            bcc_list: 密送人列表，默认为None
            file_list: 附件文件路径列表，默认为None
            content_kwargs: 模板参数，用于Jinja2模板渲染
            new_formataddr: 重置发件人信息
        Returns:
            str: 发送结果信息
        """
        if not self.check:
            return f"SMTP服务器IP={self.email_host}, 端口={self.host_port}, 发件人账号={self.email_address},请检查配置-系统配置-系统通知设置项"
        # 初始化参数
        if cc_list is None:
            cc_list = []
        if bcc_list is None:
            bcc_list = []
        if file_list is None:
            file_list = []
        # 处理收件人格式
        if isinstance(to_mail, str):
            to_mail = [to_mail]
        msg_from = self.email_address
        password = self.password
        # 处理模板渲染
        if len(content_kwargs) > 0:
            # 处理邮件标题
            subject_template = Template(subject)  # 生成模板文件
            subject = subject_template.render(content_kwargs)  # 把数据填充到模板里面
            # 处理邮件内容
            content_template = Template(content)  # 生成模板文件
            content = content_template.render(content_kwargs)  # 把数据填充到模板里面
        # 创建邮件对象
        msg = MIMEMultipart()
        # 设置邮件头信息
        logger.debug(f"msg_from={msg_from},self.email_name={self.email_name}")
        msg["From"] = new_formataddr if new_formataddr else formataddr((self.email_name, msg_from))
        msg["To"] = ",".join(to_mail)
        msg["Subject"] = Header(subject, "utf-8").encode()
        # 添加抄送和密送
        if cc_list:
            msg["Cc"] = ",".join(cc_list)
        if bcc_list:
            msg["Bcc"] = ",".join(bcc_list)
        # 添加邮件正文
        msg.attach(MIMEText(content, "html", "utf-8"))
        try:
            # 连接SMTP服务器
            if self.smtp_ssl:
                # 使用SSL连接，添加超时和调试信息
                client = smtplib.SMTP_SSL(self.email_host, self.host_port, timeout=30)
                # 启用调试模式
                # client.set_debuglevel(1)
            else:
                client = smtplib.SMTP(self.email_host, self.host_port, timeout=30)
                # client.set_debuglevel(1)
            # 登录
            if self.password:
                # 密码不等于空,登录服务器
                logger.info(f"正在尝试登录: {msg_from}")
                client.login(msg_from, password)
                logger.info("登录成功")
            # 添加附件
            for file_info in file_list:
                if isinstance(file_info, dict):
                    # 新格式：字典包含 name 和 file_url
                    file_name = file_info.get("name", "")
                    file_url = file_info.get("file_url", "")
                    # 拼接项目当前目录
                    project_root = Path(__file__).resolve().parent.parent.parent.parent
                    # 移除开头的斜杠，然后拼接项目根目录
                    relative_path = file_url.lstrip("/")
                    full_file_path = project_root / relative_path
                    logger.info(f"添加附件: {file_name} -> {full_file_path}")
                    if os.path.exists(full_file_path):
                        with open(full_file_path, "rb") as f:
                            appendix = MIMEApplication(f.read())
                            appendix.add_header(
                                "Content-Disposition", "attachment", filename=Header(file_name, "utf-8").encode()
                            )
                            msg.attach(appendix)
                    else:
                        logger.warning(f"文件不存在 {full_file_path}")
                else:
                    # 旧格式：直接是文件路径字符串
                    file_path = file_info
                    logger.info(f"添加附件: {file_path}")
                    with open(file_path, "rb") as f:
                        appendix = MIMEApplication(f.read())
                        # 获取文件名
                        filename = os.path.basename(file_path)
                        appendix.add_header(
                            "Content-Disposition", "attachment", filename=Header(filename, "utf-8").encode()
                        )
                        msg.attach(appendix)
            # 准备收件人列表（包括抄送和密送）
            all_recipients = to_mail + cc_list + bcc_list
            # 发送邮件
            client.sendmail(msg_from, all_recipients, msg.as_string())
            logger.info("邮件发送成功")

        except smtplib.SMTPAuthenticationError as e:
            logger.error(f"SMTP认证失败: {e}")
            return f"SMTP认证失败: {e}"
        except smtplib.SMTPConnectError as e:
            logger.error(f"SMTP连接失败: {e}")
            return f"SMTP连接失败: {e}"
        except smtplib.SMTPException as e:
            logger.error(f"SMTP异常: {e}")
            return f"SMTP异常: {e}"
        except Exception as e:
            logger.error(f"发生异常: {e}")
            return f"发生异常: {e}"
        finally:
            try:
                client.quit()
                logger.info("SMTP连接已关闭")
            except Exception:
                pass

        return "发送成功"


if __name__ == "__main__":
    BASE_DIR = f"{Path(__file__).resolve().parent.parent}"
    sys.path.append(BASE_DIR)
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DjangoBaseAi.settings")
    django.setup()
    logger.info(dispatch.get_system_config_values("message.smtp_ssl"))
    smtp_email = SmtpEmail()
    file_list = [{"name": "测试.xlsx", "file_url": "/media/files/76279c8125916b5c4db9b33eb85023eb.xlsx"}]
    logger.info(smtp_email.send("2256807897@qq.com", "邮件标题", "刘会飙", file_list=file_list))
