package com.jwipc.job.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.jwipc.constant.FlagConst;
import com.jwipc.job.convert.JobFileConvert;
import com.jwipc.job.dto.FileResposeDTO;
import com.jwipc.job.logic.EmailSendLogicLogic;
import com.jwipc.sys.entity.Attachment;
import com.jwipc.sys.entity.EmailLog;
import com.jwipc.sys.entity.MsgTemplate;
import com.jwipc.sys.service.IAttachmentService;
import com.jwipc.sys.service.IEmailLogService;
import com.jwipc.sys.service.IMsgTemplateService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;


/**
 * <p> </p>
 *
 * @author BOGON
 * @version 1.0
 * @since JDK 1.8
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class EmailSendLogicLogicImpl implements EmailSendLogicLogic {
    private final IEmailLogService emailLogService;
    private final JavaMailSender javaMailSender;
    private final Configuration freemarkerConfig;
    @Value("${spring.mail.username:a@b.com}")
    private String fromEmail;
    @Value("${sys.email-send-flag:false}")
    private boolean emailSendFlag;
    @Value("${sys.file-path}")
    private String filePath;
    private final IMsgTemplateService msgTemplateService;
    private final IAttachmentService attachmentService;
    private final JobFileConvert fileConvert;

    @Override
    @Async
    public void asynchSend(Collection<String> receiver, String title, String content, Long sender,
                           Collection<Long> fileIds)
    {
        for (String s : receiver) {
            asynchSend(s, title, content, sender, fileIds);
        }
    }

    @Override
    @Async
    public void asynchSend(String receiver, String title, String content, Long sender, Collection<Long> fileIds) {
        send(title, content, fileIds, sender, receiver);
    }

    @Override
    @Async
    public void asynchSend(Collection<String> receiver, String title, String templateCode, Map<String, Object> params,
                           Long sender, Collection<Long> fileIds)
    {
        for (String s : receiver) {
            asynchSend(s, title, templateCode, params, sender, fileIds);
        }
    }

    @Override
    @Async
    public void asynchSend(String receiver, String title, String templateCode, Map<String, Object> params,
                           Long sender, Collection<Long> fileIds)
    {
        syncSend(receiver, title, templateCode, params, sender, fileIds);
    }

    @Override
    public Pair<Boolean, Map<String, String>> syncSend(Collection<String> receiver, String title, String content,
                                                       Long sender, Collection<Long> fileIds)
    {
        Boolean success = true;
        Map<String, String> result = Maps.newHashMap();
        for (String s : receiver) {
            final Pair<Boolean, String> send = send(title, content, Sets.newHashSet(), sender, s);
            if (success) {
                success = send.getKey();
            }
            result.put(s, send.getValue());
        }
        return Pair.of(success, result);
    }

    @Override
    public Pair<Boolean, String> syncSend(String receiver, String title, String templateCode,
                                          Map<String, Object> params, Long sender, Collection<Long> fileIds)
    {
        final MsgTemplate one = msgTemplateService.getOne(
                new LambdaQueryWrapper<MsgTemplate>().eq(MsgTemplate::getMsgCode, templateCode));
        if (Objects.isNull(one)) {
            log.error("邮件模板未配置,配置项:{}", templateCode);
            return Pair.of(false, "邮件模板未配置");
        }
        final String content = one.getMsgContent();
        final String s = hanlderTag(content);
        final String replace = s.replace("&lt;", "<").replace("&gt;", ">");
        Template template;
        String emailContent;
        try {
            template = new Template("emailTemplate", replace, freemarkerConfig);
            emailContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, params);
            if (StrUtil.isEmpty(title)) {
                Template template1 = new Template("emailTemplate", one.getMsgName(), freemarkerConfig);
                title = FreeMarkerTemplateUtils.processTemplateIntoString(template1, params);
            }
        } catch (IOException e) {
            log.error("模板渲染失败:{}", e.getMessage());
            return Pair.of(false, "模板渲染失败");
        } catch (TemplateException e) {
            log.error("模板渲染失败:{}", e.getMessage());
            return Pair.of(false, "模板渲染失败");
        }
        return send(title, emailContent, fileIds, sender, receiver);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public Pair<Boolean, String> send(String title, String content, Collection<Long> fileIds, Long sender, String to) {
        if (!emailSendFlag) {
            log.info("==============================================================================================");
            log.info("||系统配置邮件不发送");
            log.info("||邮件标题:{}",title);
            log.info("||邮件内容:{}",content);
            log.info("||邮件附件ID:{}",fileIds);
            log.info("||邮件发送人ID:{}",sender);
            log.info("||邮件接受人:{}",to);
            log.info("==============================================================================================");
            return Pair.of(true, StrUtil.EMPTY);
        }
        String msg = "成功!";
        boolean successFlag = true;
        try {
            final MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            final MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
            mimeMessageHelper.setTo(to);
            mimeMessageHelper.setSubject(title);
            mimeMessageHelper.setFrom(fromEmail);
            mimeMessageHelper.setText(content, true);
            if (CollUtil.isNotEmpty(fileIds)) {
                final List<FileResposeDTO> forDownloads = getForDownloads(fileIds);
                if (CollUtil.isNotEmpty(forDownloads)) {
                    for (FileResposeDTO forDownload : forDownloads) {
                        mimeMessageHelper.addAttachment(forDownload.getFileName(), new File(forDownload.getFilePath()));
                    }
                }
            }
            javaMailSender.send(mimeMessage);
        } catch (MessagingException e) {
            msg = e.getMessage();
            successFlag = false;
            throw new RuntimeException(e);
        } finally {
            //记录日志
            EmailLog emailLog = new EmailLog();
            emailLog.setEmailContent(content);
            emailLog.setEmailTitle(title);
            emailLog.setToEmail(to);
            emailLog.setFromEmail(fromEmail);
            emailLog.setCreateDate(LocalDateTime.now());
            emailLog.setState(successFlag ? FlagConst.Y.getCode() : FlagConst.N.getCode());
            emailLog.setErrorMsg(msg);
            emailLog.setCreateUser(sender);
            emailLogService.save(emailLog);
        }
        return Pair.of(successFlag, msg);
    }

    public List<FileResposeDTO> getForDownloads(Collection<? extends Serializable> idList) {
        final List<Attachment> attachments = attachmentService.listByIds(idList);
        if (CollUtil.isNotEmpty(attachments)) {
            List<FileResposeDTO> result = Lists.newArrayList();
            for (Attachment attachment : attachments) {
                final FileResposeDTO abPathFileResposeDTO = getAbPathFileResposeDTO(attachment);
                result.add(abPathFileResposeDTO);
            }
            return result;
        }
        return Collections.emptyList();
    }

    private FileResposeDTO getAbPathFileResposeDTO(Attachment byId) {
        final FileResposeDTO fileResposeDTO = fileConvert.entity2DTO(byId);
        String filePath1;
        if (filePath.endsWith(File.separator)) {
            filePath1 = StrUtil.concat(true, filePath, fileResposeDTO.getFilePath());
        } else {
            filePath1 = StrUtil.concat(true, filePath, File.separator, fileResposeDTO.getFilePath());
        }
        fileResposeDTO.setFilePath(filePath1);
        return fileResposeDTO;
    }


    public static String hanlderTag(String html) {
        final Document parse = Jsoup.parse(html);
        final Elements table = parse.getElementsByTag("table");
        for (Element element : table) {
            final Elements tr = element.getElementsByTag("tr");
            if (tr.size() > 0) {
                for (Element tre : tr) {
                    final Elements td = tre.getElementsByTag("td");
                    String text = td.first().text();
                    if (text.indexOf("<#") == -1 && text.indexOf("</#") == -1) {
                        continue;
                    }
                    final int start = text.indexOf("<");
                    final int end = text.lastIndexOf(">");
                    final String substring = text.substring(start, end + 1);
                    tre.before(substring);
                    text = text.replace(substring, "");
                    td.first().text(text);
                    final Element last = td.last();
                    String lastTxt = last.text();
                    final int start1 = lastTxt.indexOf("<");
                    final int end1 = lastTxt.lastIndexOf(">");
                    final String substring1 = lastTxt.substring(start1, end1 + 1);
                    tre.after(substring1.replace("<", "&lt;").replace(">", "&gt;"));
                    lastTxt = lastTxt.replace(substring1, "");
                    last.text(lastTxt);
                }
            }
        }
        return parse.body().html();
    }
}