package com.liquidnet.service.adam.util;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.utils.PdfMerger;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.liquidnet.service.adam.constant.AdamConversionConstants;
import com.liquidnet.service.adam.constant.AdamTransactionConstants;
import com.liquidnet.service.adam.entity.AdamConversion;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.app.event.implement.IncludeRelativePath;
import org.apache.velocity.runtime.RuntimeConstants;

import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
public class PDFUtil {

    /**
     * create PDF,适合不合并的单一pdf文件
     *
     * @param paramMap 填充数据
     * @param file     输出文件
     * @param template 模板
     */
    public static boolean createPdf(Map paramMap, String file, String template) throws FileNotFoundException, DocumentException {
        // step 1
        Document document = new Document();

        // step 2
        File f = new File(file);
        // 如果目录不存在则建目录
        File tmp = f.getParentFile();
        if (!tmp.exists()) tmp.mkdirs();

        com.itextpdf.text.pdf.PdfWriter writer = com.itextpdf.text.pdf.PdfWriter.getInstance(document, new FileOutputStream(file));
        // step 3
        document.open();
        try {

            log.info("PDF file will be create as ".concat(file).concat(" | file is exist: ") + f.exists());

            // step 4
            String htmlDoc = convertToHtml(paramMap, template);

            log.debug(htmlDoc);
            // step 5
            if (htmlDoc != null) {
//                SongFontProvider fontProvider = new SongFontProvider();

                XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider();
                fontProvider.addFontSubstitute("lowagie", "garamond");
                fontProvider.setUseUnicode(true);
                /*CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
                HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
                htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
                XMLWorkerHelper.getInstance().getDefaultCssResolver(true);*/
                XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                        new ByteArrayInputStream(htmlDoc.getBytes("UTF-8")), null, Charset.forName("UTF-8"), fontProvider);
//                XMLWorkerHelper.getInstance().parseXHtml(writer, document,
//                        new ReaderInputStream(new StringReader(htmlDoc), "UTF-8"), Charset.forName("UTF-8"));
            }
        } catch (Exception e) {
            log.error("模板生成PDF文件异常", e);
        } finally {
            document.close();
            writer.close();
        }
        return f.exists();
    }

    /**
     * 创建多页pdf,适合需要合并的多页pdf
     *
     * @param paramMapList 一个map是一页pdf的参数
     * @param file         pdf文件路径,服务器地址路径
     * @param template     /resources/vm/下模板文件名
     */
    public static boolean createPdfMerger(List<Map> paramMapList, String file, String template) throws IOException {
        // step 1
        // step 2
        File f = new File(file);
        // 如果目录不存在则建目录
        File tmp = f.getParentFile();
        if (!tmp.exists()) {
            tmp.mkdirs();
        }

        // step 3
        PdfWriter writer = new PdfWriter(file);
        PdfDocument pdf = new PdfDocument(writer);
        PdfMerger merger = new PdfMerger(pdf);
        try {
            ConverterProperties properties = new ConverterProperties();
            log.info("PDF file will be create as ".concat(file).concat(" | file is exist: ") + f.exists());
            // step 4
            List<String> src = new ArrayList<>();
            for (Map map : paramMapList) {
                String htmlDoc = convertToHtml(map, template);
                src.add(htmlDoc);
            }
            for (String html : src) {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                PdfDocument temp = new PdfDocument(new PdfWriter(baos));
                HtmlConverter.convertToPdf(new ByteArrayInputStream(html.getBytes()), temp, properties);
                temp = new PdfDocument(new PdfReader(new ByteArrayInputStream(baos.toByteArray())));
                merger.merge(temp, 1, temp.getNumberOfPages());
                temp.close();
            }
            pdf.close();
        } catch (Exception e) {
            log.error("模板生成PDF文件异常", e);
        } finally {
            writer.close();
        }
        return f.exists();
    }

    public static String convertToHtml(Map<String, Object> paramMap, String templateName) throws Exception {
        try {
            log.debug("convertToHtml start.");

            VelocityEngine ve = new VelocityEngine();
            Properties p = new Properties();

//            p.put("file.resource.loader.class",
//                    "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
            p.put("eventhandler.referenceinsertion.class",
                    "org.apache.velocity.app.event.implement.EscapeXmlReference");
            p.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, IncludeRelativePath.class.getName());
            // 处理中文问题
            //可选值："class"--从classpath中读取，"file"--从文件系统中读取
            ve.setProperty("resource.loader", "class");
            //如果从文件系统中读取模板，那么属性值为org.apache.velocity.runtime.resource.loader.FileResourceLoader
            ve.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
//            ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
//            ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
//            ve.setProperty("jar.resource.loader.class", JarResourceLoader.class.getName());
            ve.setProperty(Velocity.INPUT_ENCODING, "utf-8");
            ve.setProperty(Velocity.OUTPUT_ENCODING, "utf-8");
            ve.init();
//            log.info(String.valueOf(HttpConnector.class.getClassLoader().getResource()));
            Template template = ve.getTemplate("vm/" + templateName, "UTF-8");
            // VE引擎设置PATH地址
//            ve.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, path + "/vm/");
            VelocityContext root = new VelocityContext();
            if (paramMap != null) {
                for (String key : paramMap.keySet()) {
                    root.put(key, paramMap.get(key));
                }
            }
            StringWriter wt = new StringWriter();
            template.merge(root, wt);
            wt.flush();
            return wt.getBuffer().toString();
        } catch (Exception e) {
            log.error("数据填充模板转换HTML异常", e);
            return null;
        }
    }

    /**
     * Main method
     */
    public static void main(String[] args) throws IOException, DocumentException {

        Map<String, Object> paramMap = new HashMap<>();
        AdamConversion conversion = new AdamConversion();
        conversion.setId("201111FX-000056");

        conversion.setStatus("ready_to_settle");
        conversion.setFromWalletNo("13440000001");
        conversion.setToWalletNo("11560000008");
        conversion.setSellAmount(new BigDecimal("100.0000"));
        conversion.setBuyAmount(new BigDecimal("88.1600"));
        conversion.setExecutionRate(new BigDecimal("0.881600"));
        conversion.setConversionDate(LocalDateTime.now());
        conversion.setSettlementDate(LocalDateTime.now());
        conversion.setCreateTime(LocalDateTime.now());
        conversion.setCompleteTime(LocalDateTime.now());

        paramMap.put("transactionType", AdamTransactionConstants.TypeEnum.FX_CONVERSION.getDesc());
        paramMap.put("transactionNumber", conversion.getId());
        paramMap.put("transactionCreateTime", conversion.getCreateTime());
        paramMap.put("transactionCompleteTime", conversion.getCompleteTime());
        AdamConversionConstants.StatusEnum statusEnum = AdamConversionConstants.StatusEnum.getEnumByCode(conversion.getStatus());

        paramMap.put("transactionStatus", statusEnum != null ? statusEnum.getDesc() : "");
        paramMap.put("sellAmount", conversion.getSellAmount());
        paramMap.put("buyAmount", conversion.getBuyAmount());
        paramMap.put("executionRate", conversion.getExecutionRate());
        paramMap.put("conversionDate", conversion.getConversionDate());
        paramMap.put("settlementDate", conversion.getSettlementDate());
        paramMap.put("fromWalletNo", conversion.getFromWalletNo());
        paramMap.put("toWalletNo", conversion.getToWalletNo());
        List<Map> mapList = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            mapList.add(paramMap);
        }
        // 本地生成一个多页合并的pdf文件
        PDFUtil.createPdfMerger(mapList, "/Users/lichen/Downloads/fx_conversion_1.pdf", "fx_conversion.vm");

        // 本地生成一个pdf文件
        PDFUtil.createPdf(paramMap, "/Users/lichen/Downloads/fx_conversion_2.pdf", "fx_conversion.vm");
    }

}
