package com.tykj.dev.device.file.util;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.tykj.dev.device.file.entity.*;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ResourceUtils;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.*;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author zjm
 * @version 1.0.0
 * @ClassName html.java
 * @Description TODO
 * @createTime 2021年01月23日 15:04:00
 */

public class JavaToPdfHtmlFreeMarker {
    @Value("${file.path}")
    public String url;
    @Value("${preview.path}")
    public String preview;
    private static final Map<Integer,String> MAP= new HashMap<Integer, String>() {
        {
            put(1,"第一联发机单位存");
            put(2,"第二联收机单位存");
            put(3,"第三联退发机单位存");

        }
    };

    private static final Map<Integer,String> MAP1= new HashMap<Integer, String>() {
        {
            put(1,"第一联上级1单位存");
            put(2,"第二联上级2单位存");
            put(3,"第三联本级单位存");

        }
    };
    private static final String DEST = "/Users/zjm/code/Template/HelloWorld_CN_HTML_FREEMARKER.pdf";
    private static final String HTML = "bill.html";//template_freemarker
    private static final String FONT = "/Users/zjm/code/Template/simhei.ttf";

    private static Configuration freemarkerCfg = null;

    static {
        freemarkerCfg =new Configuration();
        //freemarker的模板目录
        try {
            freemarkerCfg.setDirectoryForTemplateLoading(new File(ResourceUtils.getURL("classpath:").getPath()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) throws IOException, DocumentException {
        Documents documents=new Documents();
        documents.setNumber("NO:第221321134号");
        documents.setReceiveUnit("杭州机要");
        documents.setReplyNum("123123123131");
        documents.setSenderUnit("浙江省");
        documents.setTitle("密码装备清退单");
        List<DocumentDevice> documentDevices=new ArrayList<>();
        for (int i=0;i<20;i++){
            DocumentDevice documentDevice=new DocumentDevice();
            documentDevice.setCount(i);
            documentDevice.setModel("MM001");
            documentDevice.setRemark("备注");
            documentDevice.setApplicationField("省一级");
            documentDevice.setDeviceSerialNumber("asdq1231232");
            documentDevice.setProductionSerialNumber("12312312312");
            documentDevice.setParts("密码机");
            documentDevice.setCategory("装备");
            documentDevice.setSecurityClassification("机密");
            documentDevices.add(documentDevice);
        }
        documents.setDocumentDevices(documentDevices);
        String[] content = JavaToPdfHtmlFreeMarker.freeMarkerRender(documents,"/Users/zjm/code/test-tu/htmlModel/");
        JavaToPdfHtmlFreeMarker.createPdf(content,"/Users/zjm/code/test-tu/","12313","documents/");
    }




    public static FileRet createPdf(String[] htmlFiles,String path,String preview,String folderName){

        Long startTime = System.currentTimeMillis();
        Document document = new Document();

        String name=UUID.randomUUID().toString()+".pdf";
        String pdfPath=path+folderName+name;
        PdfCopy pdfCopy = null; //创建一个新文件
        try {
            pdfCopy = new PdfCopy(document, new FileOutputStream(pdfPath));
            document.open();
            for (String htmlFile : htmlFiles) {
                if (htmlFile != null) {
                    String url = new File(htmlFile).toURI().toURL().toString();
                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    ITextRenderer renderer = new ITextRenderer();
                    renderer.setDocument(htmlFile);
                    // 解决中文不显示问题
                    ITextFontResolver fontResolver = renderer.getFontResolver();
                    fontResolver.addFont(path+"fond/"+"simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
                    renderer.layout();
                    renderer.createPDF(os);
                    PdfReader pdfReader = new PdfReader(os.toByteArray());
                    for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
                        PdfImportedPage importedPage = pdfCopy.getImportedPage(pdfReader, i);
                        pdfCopy.addPage(importedPage);
                    }
                    os.close();
                }
            }
                Long endTime = System.currentTimeMillis();
                System.out.print("Itext parse Html to Pdf End -> " + (endTime - startTime));
            return new FileRet("", pdfPath, preview +folderName+ name);
        } catch (IOException | DocumentException | com.lowagie.text.DocumentException e) {
            e.printStackTrace();
        } finally {
            document.close();
        }
            return  new FileRet();
    }



    /**
     * freemarker渲染html
     */
    public static String[] freeMarkerRender(Documents documents,String htmlPath) {
        Writer out = new StringWriter();
        String [] strings=new String[100000];
        int index=0;
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate("bill.html");
            template.setEncoding("UTF-8");

            List<DocumentDevice> list=documents.getDocumentDevices();
            List<List<DocumentDevice>> listList=toList(list);
            int count=listList.size();
            for (int i=1; i<=3; i++){
                Integer page=1;
                for (List<DocumentDevice> list1:listList) {
                    String htmlname=htmlPath+ UUID.randomUUID().toString()+".html";
                    // 合并数据模型与模板
                    FileWriter fileWriter = new FileWriter(new File(htmlname));
                    template.process(toMap(documents,list1,MAP.get(i),page,count),fileWriter);
                    out.flush();
                    strings[index]=htmlname;
                    index++;
                    page++;
                }
            }
            return strings;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }

    private static Map<String,Object> toMap(Documents documents,List<DocumentDevice> list,String test,Integer page,Integer count){
        Map<String,Object> data = new HashMap();

        data.put("ul",test);
        data.put("number",documents.getNumber());
        data.put("title",documents.getTitle());
        data.put("receiveUnit",documents.getReceiveUnit());
        data.put("replyNum",documents.getReplyNum());
        data.put("senderUnit",documents.getSenderUnit());
        data.put("page",page);
        data.put("count",count);
        if (documents.getSrcA()==null||documents.getSrcA().equals("")){
            data.put("srcA","\""+1+"\"");
        }else {
            data.put("srcA","\""+documents.getSrcA()+"\"");
        }
        data.put("nameA",documents.getNameA());
        data.put("nameA1",documents.getNameA1());
        data.put("nameB",documents.getNameB());
        data.put("nameB1",documents.getNameB1());

        if (documents.getSrcB()==null||documents.getSrcB().equals("")){
            data.put("srcB","\""+1+"\"");
        }else {
            data.put("srcB","\""+documents.getSrcB()+"\"");
        }
        List<DocumentDevice> list1=new ArrayList<>();
        AtomicInteger i= new AtomicInteger(1);
        list.forEach(
                documentDevice -> {
                    documentDevice.setCode(i.get());
                    i.set(i.get() + 1);
                    list1.add(documentDevice);
                }
        );
        data.put("documentDevices",list1);
        return data;
    }




    private static Map<String,Object> toConfirmMap(Confirm confirm, List<DocumentDevice> list,Integer page,Integer count){
        Map<String,Object> data = new HashMap();
        data.put("title",confirm.getTitle());
        data.put("page",page);
        data.put("count",count);
        List<DocumentDevice> list1=new ArrayList<>();
        AtomicInteger i= new AtomicInteger(1);
        list.forEach(
                documentDevice -> {
                    documentDevice.setCode(i.get());
                    i.set(i.get() + 1);
                    list1.add(documentDevice);
                }
        );
        data.put("documentDevices",list1);
        return data;
    }


    private static Map<String,Object> toDestructionMap(Destruction destruction, List<DocumentDevice> list,String test,Integer page,Integer count){
        Map<String,Object> data = new HashMap();
        data.put("title",destruction.getTitle());
        data.put("ul",test);
        data.put("unitName",destruction.getDisposeUnitName());
        data.put("number",destruction.getNumber());
        Instant instant =  destruction.getTime().toInstant();
        String local1 = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        data.put("time",local1);
        data.put("page",page);
        data.put("count",count);
        List<DocumentDevice> list1=new ArrayList<>();
        AtomicInteger i= new AtomicInteger(1);
        list.forEach(
                documentDevice -> {
                    documentDevice.setCode(i.get());
                    i.set(i.get() + 1);
                    list1.add(documentDevice);
                }
        );
        data.put("documentDevices",list1);
        return data;
    }




    /**
     * freemarker渲染html  确认单据
     */
    public static String[] freeMarkerRenderConfirm(Confirm confirm,String htmlPath) {
        Writer out = new StringWriter();
        String [] strings=new String[100000];
        int index=0;
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate("bill2.html");
            template.setEncoding("UTF-8");
            List<DocumentDevice> list=confirm.getConfirmDevices().stream().sorted(Comparator.comparing(DocumentDevice::getModel)).collect(Collectors.toList());
                boolean falg=true;
                Integer page=0;
                int pageNum = page + 1;
                int pageSize = 19;
                Integer totalNum = list.size();
                //默认从零分页，这里要考虑这种情况，下面要计算。

                Integer totalPage = 0;
                while (falg){

                    if (totalNum > 0) {
                        totalPage = totalNum % pageSize == 0 ? totalNum / pageSize : totalNum / pageSize + 1;
                    }
                    if (pageNum >= totalPage) {
                        pageNum = totalPage;
                        falg=false;
                    }
                    int startPoint = (pageNum - 1) * pageSize;
                    int endPoint = startPoint + pageSize;
                    if (totalNum <= endPoint) {
                        endPoint = totalNum;
                    }

                    String htmlname=htmlPath+ UUID.randomUUID().toString()+".html";
                    // 合并数据模型与模板
                    FileWriter fileWriter = new FileWriter(new File(htmlname));
                    template.process(toConfirmMap(confirm,list.subList(startPoint, endPoint),pageNum,totalPage),fileWriter);
                    out.flush();
                    strings[index]=htmlname;
                    index++;
                    pageNum++;
            }
            return strings;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }

//    /**
//     * 确认单据页面调用接口
//     */
//    public static FileRet createPdfConfirm(String[] htmlFiles,String path,String preview,){
//
//        Long startTime = System.currentTimeMillis();
//        Document document = new Document();
//        String name=UUID.randomUUID().toString()+".pdf";
//        String pdfPath=path+"confirm/"+name;
//        PdfCopy pdfCopy = null; //创建一个新文件
//        try {
//            pdfCopy = new PdfCopy(document, new FileOutputStream(pdfPath));
//            document.open();
//            for (String htmlFile : htmlFiles) {
//                if (htmlFile != null) {
//
//                    String url = new File(htmlFile).toURI().toURL().toString();
//                    ByteArrayOutputStream os = new ByteArrayOutputStream();
//                    ITextRenderer renderer = new ITextRenderer();
//                    renderer.setDocument(htmlFile);
//                    // 解决中文不显示问题
//                    ITextFontResolver fontResolver = renderer.getFontResolver();
//                    fontResolver.addFont(path+"fond/"+"simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
//                    renderer.layout();
//                    renderer.createPDF(os);
//                    PdfReader pdfReader = new PdfReader(os.toByteArray());
//                    for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
//                        PdfImportedPage importedPage = pdfCopy.getImportedPage(pdfReader, i);
//                        pdfCopy.addPage(importedPage);
//                    }
//                    os.close();
//                }
//            }
//            Long endTime = System.currentTimeMillis();
//            System.out.print("Itext parse Html to Confirm Pdf End -> " + (endTime - startTime));
//            return new FileRet("", pdfPath, preview +"confirm/"+ name);
//        } catch (IOException | DocumentException e) {
//            e.printStackTrace();
//        } finally {
//            document.close();
//        }
//        return  new FileRet();
//    }



    /**
     * freemarker渲染html 销毁
     */
    public static String[] freeMarkerRenderDestruction(Destruction destruction,String htmlPath) {
        Writer out = new StringWriter();
        String [] strings=new String[100000];
        int index=0;
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate("bill1.html");
            template.setEncoding("UTF-8");
            List<DocumentDevice> list=destruction.getConfirmDevices();
            List<List<DocumentDevice>> listList=toList(list);
            Integer count=listList.size();
            for (int i=1; i<=3; i++){
                Integer page=1;
                for (List<DocumentDevice> list1:listList) {
                    String htmlname=htmlPath+ UUID.randomUUID().toString()+".html";
                    // 合并数据模型与模板
                    FileWriter fileWriter = new FileWriter(new File(htmlname));
                    template.process(toDestructionMap(destruction,list1,MAP1.get(i),page,count),fileWriter);
                    out.flush();
                    strings[index]=htmlname;
                    index++;
                    page++;
                }
            }
            return strings;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }


    /**
     * freemarker渲染html workHandoverDoc
     */
    public static String[] freeMarkerRenderWorkHandover(WorkHandoverDoc workHandoverDoc,String htmlPath) {
        Writer out = new StringWriter();
        String [] strings=new String[100000];
        int index=0;
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate("bill3.html");
            template.setEncoding("UTF-8");
            List<WorkHandoverDevice> list = workHandoverDoc.getWorkHandoverDeviceList();
            List<List<WorkHandoverDevice>> listList=toListWorkHandoverDevice(list);
            Integer count=listList.size();
            for (int i=1; i<=3; i++){
                Integer page=1;
                for (List<WorkHandoverDevice> list1:listList) {
                    String htmlname=htmlPath+ UUID.randomUUID().toString()+".html";
                    // 合并数据模型与模板
                    FileWriter fileWriter = new FileWriter(new File(htmlname));
                    template.process(toMapWork(workHandoverDoc,list1,MAP1.get(i),page,count),fileWriter);
                    out.flush();
                    strings[index]=htmlname;
                    index++;
                    page++;
                }
            }
            return strings;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }


    private static Map<String,Object> toMapWork(WorkHandoverDoc workHandoverDoc,List<WorkHandoverDevice> list,String test,Integer page,Integer count){
        Map<String,Object> data = new HashMap();
        Instant instant =  workHandoverDoc.getTime().toInstant();
        String local1 = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        data.put("time",local1);
        data.put("page",page);
        data.put("count",count);
        AtomicInteger i= new AtomicInteger(1);
        list.forEach(
           workHandoverDevice -> {
               workHandoverDevice.setCode(i.get());
               i.set(i.get()+1);
           }
        );

        data.put("documentDevices",list);
        return data;
    }


    public static FileRet createPdfDestruction(String[] htmlFiles,String path,String preview,String folderName){

        Long startTime = System.currentTimeMillis();
        Document document = new Document();
        String name=UUID.randomUUID().toString()+".pdf";
        String pdfPath=path+folderName+name;
        PdfCopy pdfCopy = null; //创建一个新文件
        try {
            pdfCopy = new PdfCopy(document, new FileOutputStream(pdfPath));
            document.open();
            for (String htmlFile : htmlFiles) {
                if (htmlFile != null) {

                    String url = new File(htmlFile).toURI().toURL().toString();
                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    ITextRenderer renderer = new ITextRenderer();
                    renderer.setDocument(htmlFile);
                    // 解决中文不显示问题
                    ITextFontResolver fontResolver = renderer.getFontResolver();
                    fontResolver.addFont(path+"fond/"+"simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
                    renderer.layout();
                    renderer.createPDF(os);
                    PdfReader pdfReader = new PdfReader(os.toByteArray());
                    for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
                        PdfImportedPage importedPage = pdfCopy.getImportedPage(pdfReader, i);
                        pdfCopy.addPage(importedPage);
                    }
                    os.close();
                }
            }
            Long endTime = System.currentTimeMillis();
            System.out.print("Itext parse Html to Destruction Pdf  End -> " + (endTime - startTime));
            return new FileRet("", pdfPath, preview +folderName+ name);
        } catch (IOException | DocumentException | com.lowagie.text.DocumentException e) {
            e.printStackTrace();
        } finally {
            document.close();
        }
        return  new FileRet();
    }


//    public static FileRet createPdfWordHandover(String[] htmlFiles,String path,String preview){
//
//        Long startTime = System.currentTimeMillis();
//        Document document = new Document();
//        String name=UUID.randomUUID().toString()+".pdf";
//        String pdfPath=path+"wordHandover/"+name;
//        PdfCopy pdfCopy = null; //创建一个新文件
//        try {
//            pdfCopy = new PdfCopy(document, new FileOutputStream(pdfPath));
//            document.open();
//            for (String htmlFile : htmlFiles) {
//                if (htmlFile != null) {
//
//                    String url = new File(htmlFile).toURI().toURL().toString();
//                    ByteArrayOutputStream os = new ByteArrayOutputStream();
//                    ITextRenderer renderer = new ITextRenderer();
//                    renderer.setDocument(htmlFile);
//                    // 解决中文不显示问题
//                    ITextFontResolver fontResolver = renderer.getFontResolver();
//                    fontResolver.addFont(path+"fond/"+"simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
//                    renderer.layout();
//                    renderer.createPDF(os);
//                    PdfReader pdfReader = new PdfReader(os.toByteArray());
//                    for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
//                        PdfImportedPage importedPage = pdfCopy.getImportedPage(pdfReader, i);
//                        pdfCopy.addPage(importedPage);
//                    }
//                    os.close();
//                }
//            }
//            Long endTime = System.currentTimeMillis();
//            System.out.print("Itext parse Html to Destruction Pdf  End -> " + (endTime - startTime));
//            return new FileRet("", pdfPath, preview +"wordHandover/"+ name);
//        } catch (IOException | DocumentException e) {
//            e.printStackTrace();
//        } finally {
//            document.close();
//        }
//        return  new FileRet();
//    }



    /**
     * 计算每一页打印的内容
     * 判断是否超过一页展示的最多的内容
     * 如大于
     *  直接生成一个页面的数据 放入到集合中 List<List<DocumentDevice>>
     *      不大于则计算相关的值，下一个内容
     * @param documentDevices
     * @return
     */
    private static List<List<DocumentDevice>> toList(List<DocumentDevice> documentDevices) {
        documentDevices=documentDevices.stream().sorted(Comparator.comparing(DocumentDevice::getLen).reversed()).collect(Collectors.toList());
        List<List<DocumentDevice>> lists=new ArrayList<>();
        List<DocumentDevice> list=new ArrayList<>();
        AtomicInteger count = new AtomicInteger();
        for (int i=0;i<documentDevices.size();i++){
            DocumentDevice documentDevice=documentDevices.get(i);
            int len=documentDevice.getDeviceSerialNumber().length();
            if (len>=3500){
                list.add(documentDevice);
                lists.add(list);
                list=new ArrayList<>();
            }else {
                int totle=count.get()+54+len;
                if (totle>3510){
                    DocumentDevice documentDevice1=new DocumentDevice();
                    documentDevice1.setDeviceSerialNumber(documentDevice.getDeviceSerialNumber().substring(3510-count.get(),len));
                    documentDevice.setDeviceSerialNumber(documentDevice.getDeviceSerialNumber().substring(0,3510-count.get()));
                    list.add(documentDevice);
                    lists.add(list);
                    list=new ArrayList<>();
                    list.add(documentDevice1);
                    count.set(totle-3510);
                }else {
                    list.add(documentDevice);
                    int yu=len%54;
                    int s=54-yu;
                    count.set(totle+s);
                }
            }
            if (i==documentDevices.size()-1){
                lists.add(list);
            }
        }
        return lists;

    }

    /**
     * 计算每一页打印的内容
     * 判断是否超过一页展示的最多的内容
     * 如大于
     *  直接生成一个页面的数据 放入到集合中 List<List<DocumentDevice>>
     *      不大于则计算相关的值，下一个内容
     * @param workHandoverDevices 装备数据信息
     * @return
     */
    private static List<List<WorkHandoverDevice>> toListWorkHandoverDevice(List<WorkHandoverDevice> workHandoverDevices) {
        workHandoverDevices=workHandoverDevices.stream().sorted(Comparator.comparing(WorkHandoverDevice::getLen).reversed()).collect(Collectors.toList());
        List<List<WorkHandoverDevice>> lists=new ArrayList<>();
        List<WorkHandoverDevice> list=new ArrayList<>();
        AtomicInteger count = new AtomicInteger();
        for (int i=0;i<workHandoverDevices.size();i++){
            WorkHandoverDevice workHandoverDevice=workHandoverDevices.get(i);
            int len=workHandoverDevice.getSeqs().length();
            if (len>=3500){
                workHandoverDevice.setSeqs(toString(workHandoverDevice.getSeqs()));
                list.add(workHandoverDevice);
                lists.add(list);
                list=new ArrayList<>();
            }else {
                int totle=count.get()+54+len;
                if (totle>3510){
                    WorkHandoverDevice workHandoverDevice1=new WorkHandoverDevice();
                    workHandoverDevice1.setSeqs(toString(workHandoverDevice1.getSeqs().substring(3510-count.get(),len)));
                    workHandoverDevice.setSeqs(toString(workHandoverDevice1.getSeqs().substring(0,3510-count.get())));
                    list.add(workHandoverDevice);
                    lists.add(list);
                    list=new ArrayList<>();
                    list.add(workHandoverDevice1);
                    count.set(totle-3510);
                }else {
                    workHandoverDevice.setSeqs(toString(workHandoverDevice.getSeqs()));
                    list.add(workHandoverDevice);
                    int yu=len%54;
                    int s=54-yu;
                    count.set(totle+s);
                }
            }
            if (i==workHandoverDevices.size()-1){
                workHandoverDevice.setSeqs(toString(workHandoverDevice.getSeqs()));
                lists.add(list);
            }
        }
        return lists;
    }

    private static String toString(String str){
        int len=54;
        StringBuilder stringBuilder=new StringBuilder();
        if (str.length()>54){
            boolean falg=true;
            int i=0;
            while (falg){
                if ((i+1)*len>str.length()) {
                    stringBuilder.append(str.substring(i * len)).toString();
                    falg=false;
                }else {
                    stringBuilder.append(str, i*len, (i+1)*len).append("<br/>");
                    i++;
                }
            }
            return stringBuilder.toString();
        }else {
            return str;
        }

    }

}
