package com.dxhy.core.task;


import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.dxhy.common.constant.DbConstant;
import com.dxhy.common.datasource.config.DynamicContextHolder;
import com.dxhy.common.util.MD5;
import com.dxhy.common.util.UUIDUtils;
import com.dxhy.core.job.entity.ScheduleJobEntity;
import com.dxhy.core.job.service.ScheduleJobService;
import com.dxhy.core.model.mailGather.EmailMaintainVo;
import com.dxhy.core.model.mailGather.MailGatherLogVo;
import com.dxhy.core.model.mailGather.OcrResultToyxVo;
import com.dxhy.core.model.openservice.OpenServiceOcr;
import com.dxhy.core.service.mailGather.EmailMaintainService;
import com.dxhy.core.service.mailGather.MailGatherLogService;
import com.dxhy.core.service.openservice.IOpenServicePlatformService;
import com.dxhy.core.service.openservice.impl.OpenServicePlatformServiceImpl;
import com.dxhy.core.service.openservice.model.ocr.SnpjInvoiceTypeEnum;
import com.dxhy.core.util.EmailParseUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sun.mail.pop3.POP3Folder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.mail.*;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;


@Component("snEmailGatherTask")
@Slf4j
public class SnEmailGatherTask {

    @Resource
    private ScheduleJobService scheduleJobService;
    @Resource
    private EmailMaintainService emailMaintainService;
    @Resource
    private MailGatherLogService mailGatherLogService;
    @Resource
    private IOpenServicePlatformService openServicePlatformService;
    @Value("${snyx.salt:}")
    private String snyxSalt;
    @Value("${snyx.pjurl:}")
    private String snyxPjurl;

    public void mailGatherTask(){
        DynamicContextHolder.push(DbConstant.BASICS_READ);
        ScheduleJobEntity scheduleJobEntity = scheduleJobService.queryByBeanName("snEmailGatherTask", "mailGatherTask");
        if (scheduleJobEntity != null && "0".equals(scheduleJobEntity.getJobStatus())) {
            try {
                log.info("邮箱采集接口开始--");
                scheduleJobEntity.setJobStatus("1");
                DynamicContextHolder.push(DbConstant.BASICS_WRITE);
                scheduleJobService.updateById(scheduleJobEntity);
                //进行邮件采集
                List<EmailMaintainVo> maintainVos = emailMaintainService.queryAll();
                if(maintainVos != null && !maintainVos.isEmpty()){
                    for (EmailMaintainVo maintainVo : maintainVos) {
                        //挨个邮箱进行数据采集
                        try {
                            parseEmail(maintainVo);
                        } catch (Exception e) {
                            log.error("邮箱采集错误日志：{}", e);
                            throw new RuntimeException(e);
                        }
                    }
                }else {
                    log.info("未配置邮箱数据--");
                }
                log.info("邮箱采集接口执行结束--");
            } catch (Exception e) {
                log.error("邮箱采集错误日志：{}", e);
                e.printStackTrace();
            } finally {
                log.info("邮箱采集--重置执行状态");
                scheduleJobEntity.setJobStatus("0");
                DynamicContextHolder.push(DbConstant.BASICS_WRITE);
                scheduleJobService.updateById(scheduleJobEntity);
            }
        }

    }

    public void  parseEmail(EmailMaintainVo maintainVo){
        log.info("邮箱采集内部方法开始执行--");
        long startTime = System.currentTimeMillis();
        String password = Base64Decoder.decodeStr(maintainVo.getEmailPassword());
        String emailName = maintainVo.getEmailAddress();

        try {
            Store store = mailAuth(emailName, password);
            if(store == null){
                MailGatherLogVo gatherLogVo = new MailGatherLogVo();
                gatherLogVo.setFromAddress(emailName);
                buildMsg(gatherLogVo,"1","邮箱认证失败");
                return;
            }
            Folder folder = store.getFolder("INBOX");
            //获取邮件列表
            folder.open(Folder.READ_WRITE);
            // 由于POP3协议无法获知邮件的状态,所以getUnreadMessageCount得到的是收件箱的邮件总数
            log.debug("未读邮件数: " + folder.getUnreadMessageCount());
            // 由于POP3协议无法获知邮件的状态,所以下面得到的结果始终都是为0
            log.debug("删除邮件数: " + folder.getDeletedMessageCount());
            log.debug("新邮件: " + folder.getNewMessageCount());
            // 获得收件箱中的邮件总数
            log.debug("邮件总数: " + folder.getMessageCount());
            EmailMaintainVo emailMaintainVo = new EmailMaintainVo();
            emailMaintainVo.setId(maintainVo.getId());
            Message[] messages = folder.getMessages();
            for (int i = 0, count = messages.length; i < count; i++) {
                MimeMessage msg = (MimeMessage) messages[i];
                log.debug("------------------解析第" + msg.getMessageNumber() + "封邮件-------------------- ");

                MailGatherLogVo gatherLogVo = new MailGatherLogVo();
                gatherLogVo.setId(IdUtil.nanoId());
                gatherLogVo.setSubject(EmailParseUtils.getSubject(msg));
                gatherLogVo.setFromAddress(emailName);
//                String address = EmailParseUtils.getReceiveAddress(msg, null);
                gatherLogVo.setReceiveAddress(emailName);
                String sentDate = EmailParseUtils.getSentDate(msg, null);
                gatherLogVo.setSentDate(sentDate);
                gatherLogVo.setCreateTime(new Date());

                log.debug("主题: " + EmailParseUtils.getSubject(msg));
                log.debug("发件人: " + EmailParseUtils.getFrom(msg));
//                log.debug("收件人：" + address);
                log.debug("发送时间：" + sentDate);
                log.debug("是否已读：" + EmailParseUtils.isSeen(msg));
//                log.debug("邮件优先级：" + EmailParseUtils.getPriority(msg));
//                log.debug("是否需要回执：" + EmailParseUtils.isReplySign(msg));
                log.debug("邮件大小：" + msg.getSize() * 1024 + "kb");

                POP3Folder inbox = (POP3Folder) folder;
                String uid = inbox.getUID(msg);
                if(StringUtils.isBlank(maintainVo.getEmailUid()) && i+1 == messages.length){
                    emailMaintainVo.setEmailUid(uid);
                    buildEmailMaintainVo(emailMaintainVo);
                } else if(i+1 == messages.length){
                    emailMaintainVo.setEmailUid(uid);
                    buildEmailMaintainVo(emailMaintainVo);
                }
                //增量处理  等于之后就跳过本地循环
                if(StringUtils.isNotBlank(maintainVo.getEmailUid()) && maintainVo.getEmailUid().equals(uid)){
                    log.debug("跳过本次循环： "+maintainVo.getEmailUid()+"===="+uid);
                    continue;
                }
                gatherLogVo.setMsgUid(uid);
                boolean isContainerAttachment = EmailParseUtils.isContainAttachment(msg);
                log.debug("是否有附件： "+isContainerAttachment);
                if(isContainerAttachment){
                    List<Map<String, String>> mapList = Lists.newArrayList();
                    EmailParseUtils.saveAttachment(msg, mapList);
                    log.debug("获取附件的数量："+mapList.size());
                    if(StringUtils.isNotEmpty(maintainVo.getUserId())){
                        String username = emailMaintainService.getUserByUsername(maintainVo.getUserId());
                        if(StringUtils.isNotEmpty(username)){
                            maintainVo.setUserId(username);
                        }
                    }
                    for (Map<String, String> map : mapList) {
                        map.put("emailName",emailName);
                        String pdfStream = map.get("pdfStream");
                        if(StringUtils.isNotBlank(pdfStream)){
                            log.debug("开始调用山能OCR识别---------");
                            List<OpenServiceOcr> openServiceOcrs = openServicePlatformService.ocrInvoice(pdfStream);
                            if(openServiceOcrs != null && !openServiceOcrs.isEmpty()){
                                Map<String, Object> ocrResult = convertToOcrResult(openServiceOcrs, map, maintainVo);
                                try {
                                    String md5Encode = MD5.getMd5Encode(ocrResult.get("batchId") + snyxSalt);
                                    Map<String, String> hashMap = Maps.newHashMap();
                                    hashMap.put("Authorization",md5Encode);
                                    log.info("调用影像票夹接口，调用地址：{}，请求头：{}，请求参数：{}",snyxPjurl,snyxPjurl,JSONObject.toJSONString(ocrResult));
                                    String body = HttpRequest.post(snyxPjurl).addHeaders(hashMap).body(JSONObject.toJSONString(ocrResult)).timeout(300000).execute().body();
                                    log.info("调用影像票夹接口返回参数：{}",body);
                                    Map resultMap = JSONObject.parseObject(body, Map.class);
                                    Object status = resultMap.get("status");
                                    if(status != null && "200".equals(String.valueOf(status))){
                                        gatherLogVo.setFileName(map.get("fileName"));
                                        gatherLogVo.setFileType(map.get("contentType"));
                                        buildMsg(gatherLogVo,"0","推送影像票夹成功");
                                    }else {
                                        gatherLogVo.setFphm("");
                                        buildMsg(gatherLogVo,"1","推送影像票夹失败");
                                        break;
                                    }
                                } catch (NoSuchAlgorithmException e) {
                                    throw new RuntimeException(e);
                                }

                            }else {
                                log.debug("山能OCR识别失败------");
                                buildMsg(gatherLogVo,"1","山能OCR识别失败");
                            }
                        }
                    }

                }else { //无附件的不处理
                    continue;
                }
                //进行数据插入
                if(StringUtils.isNotBlank(gatherLogVo.getFpdm()) && StringUtils.isNotBlank(gatherLogVo.getFphm())){
                    buildMsg(gatherLogVo,"0","采集成功");
                }else {
                    log.info("未采集到有效数据");
                }
            }
            // 释放资源
            folder.close(false); // false为不更新邮件，true为更新，一般在删除邮件后使用
            store.close();
            log.info("邮箱采集使用时间：{}",System.currentTimeMillis() - startTime);
        } catch (MessagingException e) {
            log.error("邮箱采集邮件解析异常:{}", e);
            throw new RuntimeException(e);
        } catch (IOException e) {
            log.error("邮箱采集IO异常:{}", e);
            throw new RuntimeException(e);
        }
    }

    public void buildEmailMaintainVo(EmailMaintainVo emailMaintainVo){
        emailMaintainService.update(emailMaintainVo);
    }


    public void buildMsg(MailGatherLogVo gatherLogVo, String type, String msg){
        gatherLogVo.setOcrType(type);
        gatherLogVo.setErrorMsg(msg);
        mailGatherLogService.insert(gatherLogVo);
    }

    public Map<String, Object> convertToOcrResult(List<OpenServiceOcr> openServiceOcrs, Map<String, String> map,EmailMaintainVo maintainVo){
        List<OcrResultToyxVo> resultToyxVoList = Lists.newArrayList();
        Map<String, Object> hashMap = Maps.newHashMap();
        String batchId = String.valueOf(System.currentTimeMillis());
        hashMap.put("batchId",batchId);

        for (int i = 0; i < openServiceOcrs.size(); i++) {
            OpenServiceOcr openServiceOcr = openServiceOcrs.get(i);
            OpenServiceOcr.InvoiceOcrData invoiceOcrData = openServiceOcr.getData();
            OcrResultToyxVo resultToyxVo = new OcrResultToyxVo();
            resultToyxVo.setCompanyId(maintainVo.getCompanyCode());
            resultToyxVo.setSource("01");
            resultToyxVo.setInvoiceCode(invoiceOcrData.getFPDM());
            resultToyxVo.setInvoiceNumber(invoiceOcrData.getFPHM());
            resultToyxVo.setTotalAmount(invoiceOcrData.getJSHJ());
            resultToyxVo.setBuyerName(invoiceOcrData.getGMFMC());
            resultToyxVo.setSellerName(invoiceOcrData.getXHFMC());
            resultToyxVo.setFileName(map.get("fileName"));
            resultToyxVo.setFileType(SnpjInvoiceTypeEnum.getVal(openServiceOcr.getFPLXDM()));
            resultToyxVo.setFileByte(map.get("pdfStream"));
            resultToyxVo.setEmail(map.get("emailName"));
            resultToyxVo.setEmployeeId(maintainVo.getUserId());
            resultToyxVoList.add(resultToyxVo);
        }
        hashMap.put("list",resultToyxVoList);


        return hashMap;
    }

    public Store mailAuth(String emailName, String password){
        //判断是否为QQ还是163
        //邮件接收协议
        String mail_protocol = "mail.store.protocol";
        //邮件接收协议类型
        String mail_protocol_type2 = "pop3";
        String mail_protocol_type = "pop";
        //邮件接收服务器端口
        String mail_port = "mail.pop3.port";
        //邮件接收服务器端口
        String port = "110";
        //邮件接收服务器地址
        String mail_host = "mail.pop3.host";
        String mailSuffix = emailName.split("@")[1];
        //邮箱类型
        String mailType = mailSuffix.split("\\.")[0];
        Properties props = new Properties();
        if(mailType.equalsIgnoreCase("qq")){
            //qq邮箱
            props.setProperty(mail_protocol, mail_protocol_type2); // 协议
            props.setProperty(mail_host, mail_protocol_type+"."+mailSuffix); // pop3服务器
            props.setProperty(mail_port, port); // 端口
        }else {
            props.setProperty(mail_protocol, mail_protocol_type); // 协议
            props.setProperty(mail_host, mail_protocol_type+"."+mailSuffix); // pop3服务器
            props.setProperty(mail_port, port); // 端口
        }
        Session session = Session.getInstance(props);
        //连接邮箱服务器

        // 创建Session实例对象
//        Session session = Session.getInstance(props,new Authenticator() {
//            protected PasswordAuthentication getPasswordAuthentication() {
//                return new PasswordAuthentication(emailName, password);
//            }
//        });
        //Session session = Session.getInstance(props);
        Store store = null;
        try {
            store = session.getStore("pop3");
            store.connect(emailName, password);
        } catch (Exception e) {
            try {
                store.close();
            } catch (MessagingException ex) {
                throw new RuntimeException(ex);
            }
            store = null;
        }
        return store;
    }

    public static void main(String[] args) {
        //邮件接收协议
        String mail_protocol = "mail.store.protocol";
        //邮件接收协议类型
        String mail_protocol_type2 = "pop3";
        String mail_protocol_type = "pop";
        //邮件接收服务器端口
        String mail_port = "mail.pop3.port";
        //邮件接收服务器端口
        String port = "110";
        //邮件接收服务器地址
        String mail_host = "mail.pop3.host";
        String emailName = "1149953701@qq.com";
        String password = "pmdzleyabmlzgdhc";
        String mailSuffix = emailName.split("@")[1];
        //邮箱类型
        String mailType = mailSuffix.split("\\.")[0];
        Properties props = new Properties();
        if(mailType.equalsIgnoreCase("qq")){
            //qq邮箱
            props.setProperty(mail_protocol, mail_protocol_type2); // 协议
            props.setProperty(mail_host, mail_protocol_type+"."+mailSuffix); // pop3服务器
            props.setProperty(mail_port, port); // 端口
        }else {
            props.setProperty(mail_protocol, mail_protocol_type2); // 协议
            props.setProperty(mail_host, mail_protocol_type2+"."+mailSuffix); // pop3服务器
            props.setProperty(mail_port, port); // 端口
        }
        Session session = Session.getInstance(props);
        Store store = null;
        try {
            store = session.getStore("pop3");
            store.connect(emailName, password);
            //连接邮箱服务器
            //获取当前时间
            Date currentTime = new Date();
            // 获得收件箱    pop3协议只有一个有效的文件夹就是INBOX
            Folder folder = store.getFolder("INBOX");
            //获取邮件列表
            folder.open(Folder.READ_WRITE);
            // 由于POP3协议无法获知邮件的状态,所以getUnreadMessageCount得到的是收件箱的邮件总数
            System.out.println("未读邮件数: " + folder.getUnreadMessageCount());
            // 由于POP3协议无法获知邮件的状态,所以下面得到的结果始终都是为0
            System.out.println("删除邮件数: " + folder.getDeletedMessageCount());
            System.out.println("新邮件: " + folder.getNewMessageCount());
            // 获得收件箱中的邮件总数
            System.out.println("邮件总数: " + folder.getMessageCount());
            Message[] messages = folder.getMessages();
            for (int i = 0, count = messages.length; i < count; i++) {
                MimeMessage msg = (MimeMessage) messages[i];
                System.out.println("------------------解析第" + msg.getMessageNumber() + "封邮件-------------------- ");
                System.out.println("主题: " + EmailParseUtils.getSubject(msg));
                System.out.println("发件人: " + EmailParseUtils.getFrom(msg));
                System.out.println("收件人：" + EmailParseUtils.getReceiveAddress(msg, null));
                System.out.println("发送时间：" + EmailParseUtils.getSentDate(msg, null));
                System.out.println("是否已读：" + EmailParseUtils.isSeen(msg));
                System.out.println("邮件优先级：" + EmailParseUtils.getPriority(msg));
                System.out.println("是否需要回执：" + EmailParseUtils.isReplySign(msg));
                System.out.println("邮件大小：" + msg.getSize() * 1024 + "kb");
                boolean isContainerAttachment = EmailParseUtils.isContainAttachment(msg);
                POP3Folder inbox = (POP3Folder) folder;
                String uid = inbox.getUID(msg);
                System.out.println("uid: ------------------" + uid);
                Flags flags = msg.getFlags();
                if (!flags.contains(Flags.Flag.SEEN)) {
                    //设置为已读
                    msg.setFlag(Flags.Flag.SEEN, true);
                }
                System.out.println("");
            }
            System.out.println("");
            Date endTime = new Date();
            //计算耗时时间
//        double elapsedTime = CalendarUtil.arithDateTime(endTime, currentTime);
            // 释放资源
            folder.close(false); // false为不更新邮件，true为更新，一般在删除邮件后使用
            store.close();
        } catch (NoSuchProviderException e) {
            throw new RuntimeException(e);
        } catch (MessagingException e) {
            throw new RuntimeException(e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
