package com.yushu.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.yushu.common.utils.DateUtils;
import com.yushu.common.utils.StringUtils;
import com.yushu.system.domain.SysMailConfig;
import com.yushu.system.domain.SysMailLog;
import com.yushu.system.domain.SysMailTemplate;
import com.yushu.system.mapper.SysMailConfigMapper;
import com.yushu.system.mapper.SysMailLogMapper;
import com.yushu.system.mapper.SysMailTemplateMapper;
import com.yushu.system.service.ISysMailService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import jakarta.mail.internet.MimeMessage;
import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 邮件发送Service实现
 * 
 * 支持：
 * 1. 阿里云企业邮箱 (SMTP)
 * 2. 腾讯企业邮箱 (SMTP)
 * 3. 网易企业邮箱 (SMTP)
 * 4. 自定义SMTP服务器
 * 
 * @author yushu
 * @date 2024-12-13
 */
@Service
public class SysMailServiceImpl implements ISysMailService {

    private static final Logger log = LoggerFactory.getLogger(SysMailServiceImpl.class);

    /** 模板变量正则表达式 */
    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{([^}]+)\\}");

    @Autowired
    private SysMailConfigMapper sysMailConfigMapper;

    @Autowired
    private SysMailTemplateMapper sysMailTemplateMapper;

    @Autowired
    private SysMailLogMapper sysMailLogMapper;

    @Override
    public boolean sendMail(String to, String subject, String content, boolean isHtml) {
        return sendMail(null, to, null, null, subject, content, isHtml);
    }

    @Override
    public boolean sendMail(Long configId, String to, String subject, String content, boolean isHtml) {
        return sendMail(configId, to, null, null, subject, content, isHtml);
    }

    @Override
    public boolean sendMail(Long configId, String to, String cc, String bcc, String subject, String content, boolean isHtml) {
        // 获取邮箱配置
        SysMailConfig config = getMailConfig(configId);
        if (config == null) {
            log.error("邮箱配置不存在或未启用");
            return false;
        }

        // 创建发送日志
        SysMailLog mailLog = new SysMailLog();
        mailLog.setConfigId(config.getConfigId());
        mailLog.setSender(config.getSenderEmail());
        mailLog.setReceiver(to);
        mailLog.setCc(cc);
        mailLog.setBcc(bcc);
        mailLog.setSubject(subject);
        mailLog.setContent(content);
        mailLog.setContentType(isHtml ? "html" : "text");
        mailLog.setStatus("2"); // 发送中
        mailLog.setSendTime(DateUtils.getNowDate());
        sysMailLogMapper.insertSysMailLog(mailLog);

        try {
            // 根据配置类型选择发送方式
            boolean result;
            if ("1".equals(config.getUseApi())) {
                // 使用API发送
                result = sendMailByApi(config, to, cc, bcc, subject, content, isHtml);
            } else {
                // 使用SMTP发送
                result = sendMailBySmtp(config, to, cc, bcc, subject, content, isHtml, null);
            }

            // 更新发送状态
            mailLog.setStatus(result ? "0" : "1");
            mailLog.setSendTime(DateUtils.getNowDate());
            sysMailLogMapper.updateSysMailLog(mailLog);

            return result;
        } catch (Exception e) {
            log.error("邮件发送失败: {}", e.getMessage(), e);
            mailLog.setStatus("1");
            mailLog.setErrorMsg(e.getMessage());
            sysMailLogMapper.updateSysMailLog(mailLog);
            return false;
        }
    }

    @Override
    public boolean sendMailWithAttachments(Long configId, String to, String subject, String content, boolean isHtml, List<String> attachmentPaths) {
        // 获取邮箱配置
        SysMailConfig config = getMailConfig(configId);
        if (config == null) {
            log.error("邮箱配置不存在或未启用");
            return false;
        }

        // 创建发送日志
        SysMailLog mailLog = new SysMailLog();
        mailLog.setConfigId(config.getConfigId());
        mailLog.setSender(config.getSenderEmail());
        mailLog.setReceiver(to);
        mailLog.setSubject(subject);
        mailLog.setContent(content);
        mailLog.setContentType(isHtml ? "html" : "text");
        mailLog.setAttachments(JSON.toJSONString(attachmentPaths));
        mailLog.setStatus("2");
        mailLog.setSendTime(DateUtils.getNowDate());
        sysMailLogMapper.insertSysMailLog(mailLog);

        try {
            boolean result = sendMailBySmtp(config, to, null, null, subject, content, isHtml, attachmentPaths);
            mailLog.setStatus(result ? "0" : "1");
            mailLog.setSendTime(DateUtils.getNowDate());
            sysMailLogMapper.updateSysMailLog(mailLog);
            return result;
        } catch (Exception e) {
            log.error("邮件发送失败: {}", e.getMessage(), e);
            mailLog.setStatus("1");
            mailLog.setErrorMsg(e.getMessage());
            sysMailLogMapper.updateSysMailLog(mailLog);
            return false;
        }
    }

    @Override
    public boolean sendMailByTemplate(String templateCode, String to, Map<String, Object> variables) {
        return sendMailByTemplate(null, templateCode, to, variables);
    }

    @Override
    public boolean sendMailByTemplate(Long configId, String templateCode, String to, Map<String, Object> variables) {
        // 获取模板
        SysMailTemplate template = sysMailTemplateMapper.selectSysMailTemplateByCode(templateCode);
        if (template == null) {
            log.error("邮件模板不存在: {}", templateCode);
            return false;
        }

        // 渲染主题和内容
        String subject = renderContent(template.getSubject(), variables);
        String content = renderContent(template.getContent(), variables);
        boolean isHtml = "html".equals(template.getContentType());

        // 获取邮箱配置
        SysMailConfig config = getMailConfig(configId);
        if (config == null) {
            log.error("邮箱配置不存在或未启用");
            return false;
        }

        // 创建发送日志
        SysMailLog mailLog = new SysMailLog();
        mailLog.setConfigId(config.getConfigId());
        mailLog.setTemplateId(template.getTemplateId());
        mailLog.setSender(config.getSenderEmail());
        mailLog.setReceiver(to);
        mailLog.setSubject(subject);
        mailLog.setContent(content);
        mailLog.setContentType(template.getContentType());
        mailLog.setStatus("2");
        mailLog.setSendTime(DateUtils.getNowDate());
        sysMailLogMapper.insertSysMailLog(mailLog);

        try {
            boolean result;
            if ("1".equals(config.getUseApi())) {
                result = sendMailByApi(config, to, null, null, subject, content, isHtml);
            } else {
                result = sendMailBySmtp(config, to, null, null, subject, content, isHtml, null);
            }
            
            mailLog.setStatus(result ? "0" : "1");
            mailLog.setSendTime(DateUtils.getNowDate());
            sysMailLogMapper.updateSysMailLog(mailLog);
            return result;
        } catch (Exception e) {
            log.error("邮件发送失败: {}", e.getMessage(), e);
            mailLog.setStatus("1");
            mailLog.setErrorMsg(e.getMessage());
            sysMailLogMapper.updateSysMailLog(mailLog);
            return false;
        }
    }

    @Override
    public boolean resendMail(Long logId) {
        SysMailLog mailLog = sysMailLogMapper.selectSysMailLogByLogId(logId);
        if (mailLog == null) {
            log.error("邮件发送记录不存在: {}", logId);
            return false;
        }

        // 获取配置
        SysMailConfig config = sysMailConfigMapper.selectSysMailConfigByConfigId(mailLog.getConfigId());
        if (config == null || "1".equals(config.getStatus())) {
            log.error("邮箱配置不存在或已停用");
            return false;
        }

        try {
            boolean isHtml = "html".equals(mailLog.getContentType());
            boolean result;

            if ("1".equals(config.getUseApi())) {
                result = sendMailByApi(config, mailLog.getReceiver(), mailLog.getCc(), mailLog.getBcc(),
                        mailLog.getSubject(), mailLog.getContent(), isHtml);
            } else {
                List<String> attachments = null;
                if (StringUtils.isNotEmpty(mailLog.getAttachments())) {
                    attachments = JSON.parseArray(mailLog.getAttachments(), String.class);
                }
                result = sendMailBySmtp(config, mailLog.getReceiver(), mailLog.getCc(), mailLog.getBcc(),
                        mailLog.getSubject(), mailLog.getContent(), isHtml, attachments);
            }

            // 更新状态
            mailLog.setStatus(result ? "0" : "1");
            mailLog.setSendTime(DateUtils.getNowDate());
            if (result) {
                mailLog.setErrorMsg(null);
            }
            sysMailLogMapper.updateSysMailLog(mailLog);

            return result;
        } catch (Exception e) {
            log.error("邮件重发失败: {}", e.getMessage(), e);
            mailLog.setErrorMsg(e.getMessage());
            sysMailLogMapper.updateSysMailLog(mailLog);
            return false;
        }
    }

    /**
     * 获取邮箱配置
     */
    private SysMailConfig getMailConfig(Long configId) {
        if (configId != null) {
            SysMailConfig config = sysMailConfigMapper.selectSysMailConfigByConfigId(configId);
            if (config != null && "0".equals(config.getStatus())) {
                return config;
            }
        }
        // 获取默认配置
        return sysMailConfigMapper.selectDefaultConfig();
    }

    /**
     * 使用SMTP发送邮件
     */
    private boolean sendMailBySmtp(SysMailConfig config, String to, String cc, String bcc,
                                   String subject, String content, boolean isHtml, List<String> attachmentPaths) {
        try {
            JavaMailSenderImpl mailSender = createMailSender(config);
            MimeMessage message = mailSender.createMimeMessage();
            
            boolean hasAttachment = attachmentPaths != null && !attachmentPaths.isEmpty();
            MimeMessageHelper helper = new MimeMessageHelper(message, hasAttachment, "UTF-8");

            // 设置发件人
            String from = StringUtils.isNotEmpty(config.getSenderName()) 
                ? config.getSenderName() + " <" + config.getSenderEmail() + ">"
                : config.getSenderEmail();
            helper.setFrom(from);

            // 设置收件人
            helper.setTo(to.split(","));

            // 设置抄送
            if (StringUtils.isNotEmpty(cc)) {
                helper.setCc(cc.split(","));
            }

            // 设置密送
            if (StringUtils.isNotEmpty(bcc)) {
                helper.setBcc(bcc.split(","));
            }

            // 设置主题和内容
            helper.setSubject(subject);
            helper.setText(content, isHtml);

            // 添加附件
            if (hasAttachment) {
                for (String path : attachmentPaths) {
                    File file = new File(path);
                    if (file.exists()) {
                        FileSystemResource resource = new FileSystemResource(file);
                        helper.addAttachment(file.getName(), resource);
                    }
                }
            }

            // 发送邮件
            mailSender.send(message);
            log.info("邮件发送成功: to={}, subject={}", to, subject);
            return true;
        } catch (Exception e) {
            log.error("SMTP邮件发送失败: {}", e.getMessage(), e);
            throw new RuntimeException("邮件发送失败: " + e.getMessage());
        }
    }

    /**
     * 使用API发送邮件（预留接口，可扩展阿里云、腾讯云等API）
     */
    private boolean sendMailByApi(SysMailConfig config, String to, String cc, String bcc,
                                  String subject, String content, boolean isHtml) {
        String mailType = config.getMailType();
        
        switch (mailType) {
            case "aliyun":
                return sendMailByAliyunApi(config, to, cc, bcc, subject, content, isHtml);
            case "tencent":
                return sendMailByTencentApi(config, to, cc, bcc, subject, content, isHtml);
            default:
                // 默认使用SMTP方式
                return sendMailBySmtp(config, to, cc, bcc, subject, content, isHtml, null);
        }
    }

    /**
     * 阿里云API发送邮件
     * 注意：需要添加阿里云SDK依赖
     */
    private boolean sendMailByAliyunApi(SysMailConfig config, String to, String cc, String bcc,
                                        String subject, String content, boolean isHtml) {
        // TODO: 集成阿里云DirectMail SDK
        // 目前使用SMTP方式作为备选
        log.info("阿里云API发送暂未实现，使用SMTP方式发送");
        return sendMailBySmtp(config, to, cc, bcc, subject, content, isHtml, null);
    }

    /**
     * 腾讯云API发送邮件
     * 注意：需要添加腾讯云SDK依赖
     */
    private boolean sendMailByTencentApi(SysMailConfig config, String to, String cc, String bcc,
                                         String subject, String content, boolean isHtml) {
        // TODO: 集成腾讯云邮件SDK
        // 目前使用SMTP方式作为备选
        log.info("腾讯云API发送暂未实现，使用SMTP方式发送");
        return sendMailBySmtp(config, to, cc, bcc, subject, content, isHtml, null);
    }

    /**
     * 创建JavaMailSender
     */
    private JavaMailSenderImpl createMailSender(SysMailConfig config) {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        
        // 根据邮箱类型设置默认配置
        String mailType = config.getMailType();
        switch (mailType) {
            case "aliyun":
                mailSender.setHost(StringUtils.isNotEmpty(config.getHost()) ? config.getHost() : "smtp.qiye.aliyun.com");
                mailSender.setPort(config.getPort() != null ? config.getPort() : 465);
                break;
            case "tencent":
                mailSender.setHost(StringUtils.isNotEmpty(config.getHost()) ? config.getHost() : "smtp.exmail.qq.com");
                mailSender.setPort(config.getPort() != null ? config.getPort() : 465);
                break;
            case "netease":
                mailSender.setHost(StringUtils.isNotEmpty(config.getHost()) ? config.getHost() : "smtp.qiye.163.com");
                mailSender.setPort(config.getPort() != null ? config.getPort() : 465);
                break;
            default:
                mailSender.setHost(config.getHost());
                mailSender.setPort(config.getPort() != null ? config.getPort() : 25);
        }

        // 设置用户名和密码
        mailSender.setUsername(config.getUsername());
        mailSender.setPassword(config.getPassword());
        mailSender.setDefaultEncoding("UTF-8");

        // 设置邮件属性
        Properties props = mailSender.getJavaMailProperties();
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.timeout", "25000");
        props.put("mail.smtp.connectiontimeout", "25000");

        // 设置加密方式
        String encryption = config.getEncryption();
        if ("ssl".equals(encryption)) {
            props.put("mail.smtp.ssl.enable", "true");
            props.put("mail.smtp.ssl.trust", mailSender.getHost());
            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            props.put("mail.smtp.socketFactory.fallback", "false");
            props.put("mail.smtp.socketFactory.port", String.valueOf(mailSender.getPort()));
        } else if ("tls".equals(encryption)) {
            props.put("mail.smtp.starttls.enable", "true");
            props.put("mail.smtp.starttls.required", "true");
        }

        // 额外参数
        if (StringUtils.isNotEmpty(config.getExtraParams())) {
            try {
                JSONObject extraParams = JSON.parseObject(config.getExtraParams());
                for (String key : extraParams.keySet()) {
                    props.put(key, extraParams.getString(key));
                }
            } catch (Exception e) {
                log.warn("解析额外参数失败: {}", e.getMessage());
            }
        }

        return mailSender;
    }

    /**
     * 渲染模板内容
     */
    private String renderContent(String content, Map<String, Object> variables) {
        if (StringUtils.isEmpty(content) || variables == null || variables.isEmpty()) {
            return content;
        }
        
        StringBuffer result = new StringBuffer();
        Matcher matcher = VARIABLE_PATTERN.matcher(content);
        
        while (matcher.find()) {
            String variableName = matcher.group(1);
            Object value = variables.get(variableName);
            String replacement = value != null ? value.toString() : "";
            replacement = Matcher.quoteReplacement(replacement);
            matcher.appendReplacement(result, replacement);
        }
        matcher.appendTail(result);
        
        return result.toString();
    }
}
