package com.reptileclient.jlifeapp.util.email;

import com.reptileclient.jlifeapp.util.page.DownloadUtil;
import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPStore;
import com.sun.mail.imap.protocol.IMAPProtocol;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.mail.*;
import javax.mail.internet.MimeUtility;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static cn.hutool.core.date.DatePattern.NORM_DATETIME_PATTERN;

/**
 * 读取邮箱
 */
@Service
public class EmailUtils {


    private static boolean needWaitDownload = false;

    /**
     * 获取邮箱信息
     *
     * @param host
     * @param username
     * @param password
     * @return
     * @throws MessagingException
     */
    public static Message[] getWEMessage(String host, String username, String password, Integer port) throws MessagingException {
        //创建属性对象
//        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        Properties props = System.getProperties();
        props.setProperty("mail.smtp.host", host);
        props.setProperty("mail.store.protocol", "imap");
        props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.setProperty("mail.smtp.socketFactory.fallback", "false");
        props.setProperty("mail.smtp.port", port.toString());//设置端口
        props.setProperty("mail.debug", "false");//启用调试
        props.setProperty("mail.smtp.auth", "true");
        //建立邮件会话
        Session session = Session.getInstance(props);
        IMAPStore store = (IMAPStore) session.getStore("imap");

        store.connect(host, port, username, password);
        //创建目录对象
        Folder folder = store.getFolder("INBOX");
        if (folder instanceof IMAPFolder) {
            IMAPFolder imapFolder = (IMAPFolder) folder;
            //javamail中使用id命令有校验checkOpened, 所以要去掉id方法中的checkOpened();
            imapFolder.doCommand(new IMAPFolder.ProtocolCommand() {
                public Object doCommand(IMAPProtocol p) throws com.sun.mail.iap.ProtocolException {
                    p.id("FUTONG");
                    return null;
                }
            });
        }

        if (folder != null) {
            folder.open(Folder.READ_WRITE);
        }
        return folder.getMessages();
    }

    /**
     * 过滤邮箱信息
     *
     * @param messages
     * @param fromMail  只读取该邮箱发来的邮件，如果为空则不过滤
     * @param startDate 只读取该日期以后的邮件，如果为空则不过滤
     * @param endDate
     * @return
     * @throws MessagingException
     */
    public static List<Message> filterMessage(Message[] messages, String fromMail, String startDate, String endDate) throws MessagingException, ParseException {
        List<Message> messageList = new ArrayList<>();
        if (ObjectUtils.isEmpty(messages)) {
            return messageList;
        }
        boolean isEnptyFromMail = ObjectUtils.isEmpty(fromMail);
        boolean isEnptyStartDate = ObjectUtils.isEmpty(startDate);
        if (isEnptyFromMail && isEnptyStartDate) {
            return Arrays.asList(messages);
        }

        String from;
        for (Message message : messages) {
            from = null;
            if (message.getFrom() != null) {
                from = (message.getFrom()[0]).toString();
            }
            if (isEnptyFromMail) {
                if (message.getSentDate() != null && new SimpleDateFormat(NORM_DATETIME_PATTERN).parse(startDate).getTime() > message.getSentDate().getTime()) {
                    continue;
                }
                if (message.getSentDate() != null && new SimpleDateFormat(NORM_DATETIME_PATTERN).parse(endDate).getTime() < message.getSentDate().getTime()) {
                    continue;
                }
            } else if (null != from && from.contains(fromMail)) {
                if (!isEnptyStartDate && new SimpleDateFormat(NORM_DATETIME_PATTERN).parse(startDate).getTime() > message.getSentDate().getTime()) {
                    continue;
                }
                if (message.getSentDate() != null && new SimpleDateFormat(NORM_DATETIME_PATTERN).parse(endDate).getTime() < message.getSentDate().getTime()) {
                    continue;
                }
            } else {
                continue;
            }
            messageList.add(message);
        }
        return messageList;
    }


    /**
     * 判断此邮件是否包含附件
     *
     * @param part
     * @return
     * @throws MessagingException
     * @throws IOException
     */
    public static boolean isContainAttach(Part part) throws MessagingException, IOException {
        boolean attachFlag = false;
        if (part.isMimeType("multipart/*")) {
            Multipart mp = (Multipart) part.getContent();
            BodyPart mPart;
            String conType;
            for (int i = 0; i < mp.getCount(); i++) {
                mPart = mp.getBodyPart(i);
                String disposition = mPart.getDisposition();
                if (Part.ATTACHMENT.equals(disposition) || Part.INLINE.equals(disposition)) {
                    attachFlag = true;
                } else if (mPart.isMimeType("multipart/*")) {
                    attachFlag = isContainAttach(mPart);
                } else if (mPart.isMimeType("text/plain")) {
                    attachFlag = true;
                } else {
                    conType = mPart.getContentType();
                    if (conType.toLowerCase().contains("application") || conType.toLowerCase().contains("name")) {
                        attachFlag = true;
                    }
                }
            }
        } else if (part.isMimeType("message/rfc822")) {
            attachFlag = isContainAttach((Part) part.getContent());
        }
        return attachFlag;
    }

    /**
     * 保存附件
     *
     * @param part
     * @throws MessagingException
     * @throws IOException
     */
    public static void saveAttachMent(Part part) throws MessagingException, IOException {
        String fileName;
        if (part.isMimeType("multipart/*")) {
            Multipart mp = (Multipart) part.getContent();
            BodyPart mPart;
            for (int i = 0; i < mp.getCount(); i++) {
                mPart = mp.getBodyPart(i);
                String disposition = mPart.getDisposition();
                if (Part.ATTACHMENT.equals(disposition) || Part.INLINE.equals(disposition)) {
                    fileName = mPart.getFileName();
                    if (null != fileName && fileName.toLowerCase().contains("utf-8")) {
                        fileName = MimeUtility.decodeText(fileName);
                    }
                    saveFile(fileName, mPart.getInputStream());
                } else if (mPart.isMimeType("multipart/*")) {
                    Multipart innermp = (Multipart) mPart.getContent();
                    for (int i1 = 0; i1 < innermp.getCount(); i1++) {
                        if (innermp.getBodyPart(i).isMimeType("text/plain")) {
                            String content = innermp.getBodyPart(i).getContent().toString();
                            //解析这里的超大附件
                            if (!StringUtils.isEmpty(content)) {
                                //提取超大文件名称
                                int start = content.indexOf("超大附件列表");
                                needWaitDownload = start != -1;
                                if (needWaitDownload) {
                                    int end = content.lastIndexOf("[");
                                    String bigFileName = content.substring(start + 6, end);
                                    if (!StringUtils.isEmpty(bigFileName)) {
                                        bigFileName = bigFileName.trim();
                                        String keyWord = "进入下载页面";
                                        int keyIndex = content.indexOf(keyWord);
                                        String transit = content.substring(keyIndex + keyWord.length()).trim();
                                        if (!transit.contains("https")) {
                                            continue;
                                        }
                                        String fileId = URLDecoder.decode(transit, "UTF-8").split("\\?id=")[1];
                                        String downUrl = "https://webmail.alibaba-inc.com/attachment/gdown/"
                                                + URLEncoder.encode(bigFileName, "utf-8")
                                                + "?itemid=" + URLEncoder.encode(fileId, "utf-8");
                                        //这里直接下载downurl
                                        System.out.println("bigFileName:" + bigFileName + " downUrl:" + downUrl);
                                        if (!isFileExist(getFileDir() + ".success")) {
                                            DownloadUtil.getInstance(downUrl, getFileDir() + bigFileName).download();
                                        }
                                    }
                                }


                            }
                        }
                    }
                } else {
                    fileName = mPart.getFileName();
                    if ((fileName != null) && (fileName.toLowerCase().contains("utf-8"))) {
                        fileName = MimeUtility.decodeText(fileName);
                        saveFile(fileName, mPart.getInputStream());
                    }
                }
            }
        }
        writeSuccessFile();
    }

    /**
     * 真正的保存附件到指定目录里
     *
     * @param fileName
     * @param in
     * @throws IOException
     */
    private static void saveFile(String fileName, InputStream in) throws IOException {
        String storeDir = getFileDir();

        //保存目录不存在 创建一个
        File file = new File(storeDir);
        if (!file.exists()) file.mkdirs();

        FileOutputStream fos = new FileOutputStream(storeDir + File.separator + fileName);
        IOUtils.copy(in, fos);
        IOUtils.closeQuietly(fos);
        IOUtils.closeQuietly(in);

    }

    @NotNull
    public static String getFileDir() {
        String dayDir = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")).substring(4);
        String osName = System.getProperty("os.name");
        String storeDir = "";
        if (null == osName) {
            osName = "";
        }
        if (osName.toLowerCase().contains("win")) {
            if (ObjectUtils.isEmpty(storeDir))
                storeDir = "c:\\temp\\";
        } else if (osName.toLowerCase().contains("mac")) {
            storeDir = "../tmp/" + dayDir + "/";
        } else {
            storeDir = "/data0/file/" + dayDir + "/";
        }
        return storeDir;
    }


    public static void main(String[] args) throws MessagingException, IOException, ParseException {
        //163登录信息
        //邮件服务器
        String host = "imap.qiye.aliyun.com";
        //邮箱账号
        String username = "documents@lifejingzhi.com";
        //授权码
        String password = "JZSHjzsh123456";
        //协议
        String protocol = "imap";
        //只读取该邮箱发来的邮件
        String fromMail = null;
        //只读取该日期以后的邮件
        String thisDay = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String x = LocalDateTime.parse(thisDay + "T00:00:00").format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        String y = LocalDateTime.parse(thisDay + "T23:59:59").format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        downLoad(host, username, password, x, y);
    }

    public static void downLoad(String host, String userName, String password, String startDate, String endDate) throws MessagingException, IOException, ParseException {
        List<Message> messageList = filterMessage(getWEMessage(host, userName, password, 143), "alibaba-inc.com", startDate, endDate);
        if (messageList.isEmpty()) {
            return;
        }
        for (Message message : messageList) {
            if (isContainAttach(message)) {
                saveAttachMent(message);
            }
        }
    }

    private static void writeSuccessFile() {
        String fileDir = getFileDir().substring(0, getFileDir().length() - 1);
        boolean b = false;
        if (needWaitDownload) {
            while (!b) {
                try {
                    Thread.sleep(1000 * 5);
                    File file = new File(fileDir);
                    b = Arrays.stream(Objects.requireNonNull(file.listFiles())).anyMatch(a -> a.getName().contains(".success"));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        File dir = new File(fileDir);
        if (!dir.exists()) {
            boolean mkdirs = dir.mkdirs();
            if (!mkdirs) {
                System.out.println("创建文件夹失败");
            }
        }
        File file = new File(dir + "/success.txt");
        if (file.exists()) {
            file.delete();
        }
        try {
            file.createNewFile();
        } catch (IOException e) {
            System.out.println("创建文件失败，失败原因：" + e.getMessage());
        }
        needWaitDownload = false;
    }

    public static boolean isFileExist(String s) {
        File file = new File(s);
        return file.exists();
    }
}
