package com.qmth.distributed.print.business.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.qmth.distributed.print.business.bean.dto.PdfPackageDto;
import com.qmth.distributed.print.business.bean.dto.PdfSignDto;
import com.qmth.distributed.print.business.bean.examRule.CodeNameEnableRate;
import com.qmth.distributed.print.business.entity.BasicTemplate;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.FontSizeEnum;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

/**
 * pdf模板内容填充
 */
@Component
public class CreatePrintPdfUtil {
    private static final Logger log = LoggerFactory.getLogger(CreatePrintPdfUtil.class);

    /**
     * 签到表生成
     *
     * @param pdfFillDto    签到表数据
     * @param destFileName  文件名
     * @param basicTemplate 印品
     */
    public File createSignPdf(PdfSignDto pdfFillDto, String destFileName, BasicTemplate basicTemplate) throws Exception {

        // 1:建立Document对象实例
        Document document = new Document(PageSize.A4, 20F, 20F, 40F, 36F);
//        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        File file = createFolder(destFileName);
        FileOutputStream fos = null;
        PdfWriter pdfWriter = null;
        try {
            // 2:建立一个PDF 写入器与document对象关联通过书写器(Writer)可以将文档写入到磁盘中
            fos = new FileOutputStream(file);
            pdfWriter = PdfWriter.getInstance(document, fos);

            //3、设置pdf页眉和页脚和水印
            MyHeaderFooter headerFooter = new MyHeaderFooter(pdfFillDto.getPackageNumber());
            pdfWriter.setPageEvent(headerFooter);

            // 3:打开文档
            document.open();
            //生成pdf
            this.generateSignPDF(document, pdfWriter, pdfFillDto, basicTemplate);
            // 5:关闭文档
            document.close();


        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                fos.close();
            }
            if (pdfWriter != null) {
                pdfWriter.close();
            }
        }
        return file;
    }

    /**
     * 卷袋贴生成
     *
     * @param pdfPackageDto 卷袋贴参数
     * @param destFileName  保存文件名
     */
    public File createPackagePdf(PdfPackageDto pdfPackageDto, String destFileName) throws Exception {

        // 1:建立Document对象实例
        Document document = new Document(PageSize.A4, 36.0F, 36.0F, 40F, 36.0F);
//        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        File file = createFolder(destFileName);
        FileOutputStream fos = null;
        PdfWriter pdfWriter = null;
        try {
            // 2:建立一个PDF 写入器与document对象关联通过书写器(Writer)可以将文档写入到磁盘中
            fos = new FileOutputStream(file);
            pdfWriter = PdfWriter.getInstance(document, fos);
            // 3:打开文档
            document.open();
            //生成pdf
            this.generatePackagePDF(document, pdfWriter, pdfPackageDto);
            // 5:关闭文档
            document.close();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                fos.close();
            }
            if (pdfWriter != null) {
                pdfWriter.close();
            }
        }

        return file;
    }

    /**
     * 生成签到表pdf文件
     *
     * @param document   document
     * @param pdfWriter  pdfWriter
     * @param pdfFillDto 签到表数据
     */
    private void generateSignPDF(Document document, PdfWriter pdfWriter, PdfSignDto pdfFillDto, BasicTemplate basicTemplate) throws DocumentException {
        Boolean diallel = basicTemplate == null || basicTemplate.getDiallel() == null ? true : basicTemplate.getDiallel();
        Double lineHeightTimes = basicTemplate == null || basicTemplate.getLineHeightTimes() == null ? 1 : basicTemplate.getLineHeightTimes();

        // 空格
        Paragraph blank = new Paragraph(" ");
        // 标题table
//        PdfPTable titleTable = PdfFillUtils.createTable(new float[]{100});
//        titleTable.addCell(PdfFillUtils.createCell(pdfFillDto.getTitle(), PdfFillUtils.textFont16, null, Element.ALIGN_CENTER, 15, 3, 1));
//        titleTable.getDefaultCell().setFixedHeight(50f);
//        document.add(titleTable);


        // 基础信息表格
        PdfPTable basicTable = PdfFillUtils.createTable(6);
        basicTable.addCell(PdfFillUtils.createTitleCell(pdfFillDto.getTitle(), PdfFillUtils.textFont16, 60f, 15, 1, 6));
        List<Map<String, String>> basicPlate = pdfFillDto.getBasicPlate();
        for (Map<String, String> stringMap : basicPlate) {
            basicTable.addCell(PdfFillUtils.createCell(stringMap.get("name") + "：" + stringMap.get("value"), PdfFillUtils.textFont10, null, Element.ALIGN_LEFT, 0, 1, 3));
        }
        if (basicPlate.size() % 2 > 0) {
            basicTable.addCell(PdfFillUtils.createCell(" ", PdfFillUtils.textFont10, null, Element.ALIGN_LEFT, 0, 1, 3));
        }
        document.add(basicTable);

        document.add(blank);

        //表头
        Map<String, String> studentHeadPlate = pdfFillDto.getStudentHeadPlate();
        //计算表格宽度
        float[] columnWidth = createColumnWidth(basicTemplate);
        int columnCount = studentHeadPlate.size();

        PdfPTable studentTable = PdfFillUtils.createTable(columnWidth);

        // 双列
        if (diallel) {
            String[] headKeys = new String[columnCount * 2];
            for (int i = 0; i < 2; i++) {
                int j = 0;
                for (Map.Entry<String, String> entry : studentHeadPlate.entrySet()) {
                    headKeys[columnCount * i + j] = entry.getKey();
                    String value = entry.getValue();
                    if ("座位号".equals(value)) {
                        value = "座号";
                    }
                    studentTable.addCell(PdfFillUtils.createCell1(lineHeightTimes, value, chooseFont(basicTemplate), BaseColor.LIGHT_GRAY, Element.ALIGN_CENTER, 0, 1, 1));
                    j++;
                }
            }

            //数据
            List<Map<String, String>> studentPlate = pdfFillDto.getStudentPlate();
            int studentPlateCount = studentPlate.size();
            int forCount = studentPlateCount % 2 == 0 ? studentPlateCount / 2 : studentPlateCount / 2 + 1;

            for (int i = 0; i < forCount; i++) {
                Map<String, String> stringMap1 = studentPlate.get(2 * i);
                for (int j = 0; j < stringMap1.size(); j++) {
                    String value = stringMap1.get(headKeys[j]);
                    studentTable.addCell(PdfFillUtils.createCell1(lineHeightTimes, value, chooseFont(basicTemplate), null, Element.ALIGN_CENTER, 0, 1, 1));
                }

                if (studentPlateCount % 2 > 0 && 2 * i + 1 == studentPlate.size()) {
                    for (int i1 = 0; i1 < columnCount; i1++) {
                        studentTable.addCell(PdfFillUtils.createCell1(lineHeightTimes, "", chooseFont(basicTemplate), null, Element.ALIGN_CENTER, 0, 1, 1));
                    }
                    continue;
                }
                Map<String, String> stringMap2 = studentPlate.get(2 * i + 1);
                for (int j = 0; j < stringMap2.size(); j++) {
                    String value = stringMap2.get(headKeys[j + columnCount]);
                    studentTable.addCell(PdfFillUtils.createCell1(lineHeightTimes, value, chooseFont(basicTemplate), null, Element.ALIGN_CENTER, 0, 1, 1));
                }
            }
        }
        // 单列
        else {
            String[] headKeys = new String[columnCount];
            int k = 0;
            for (Map.Entry<String, String> entry : studentHeadPlate.entrySet()) {
                headKeys[k] = entry.getKey();
                String value = entry.getValue();
                if ("座位号".equals(value)) {
                    value = "座号";
                }
                studentTable.addCell(PdfFillUtils.createCell1(lineHeightTimes, value, chooseFont(basicTemplate), BaseColor.LIGHT_GRAY, Element.ALIGN_CENTER, 0, 1, 1));
                k++;
            }

            //数据
            List<Map<String, String>> studentPlate = pdfFillDto.getStudentPlate();
            int studentPlateCount = studentPlate.size();

            for (int i = 0; i < studentPlateCount; i++) {
                Map<String, String> stringMap1 = studentPlate.get(i);
                for (int j = 0; j < stringMap1.size(); j++) {
                    String value = stringMap1.get(headKeys[j]);
                    studentTable.addCell(PdfFillUtils.createCell1(lineHeightTimes, value, chooseFont(basicTemplate), null, Element.ALIGN_CENTER, 0, 1, 1));
                }
            }
        }
        //将表格的第一行设置为表头 让它在每一页都显示出来
        studentTable.setHeaderRows(1);
        document.add(studentTable);

        document.add(blank);

        // 文字说明
        if (StringUtils.isNotBlank(pdfFillDto.getTextDesc())) {
            Paragraph textDesc = new Paragraph(pdfFillDto.getTextDesc(), PdfFillUtils.textFont9);
            document.add(textDesc);

            document.add(blank);
        }

        Paragraph pDate = new Paragraph(" 年        月        日", PdfFillUtils.textFont9);
        pDate.setAlignment(Element.ALIGN_RIGHT);
        pDate.setIndentationRight(20);

        PdfPTable signTable = new PdfPTable(4);
        signTable.setWidthPercentage(100);// 表格宽度为100%
        // 备注
        PdfPCell cell34 = new PdfPCell();
        cell34.setBorderWidth(0.5F);
        cell34.setMinimumHeight(20);
        cell34.setPhrase(new Paragraph("监考老师签名处", PdfFillUtils.textFont9));
        cell34.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell34.setHorizontalAlignment(Element.ALIGN_CENTER);
        signTable.addCell(cell34);
        PdfPCell cell35 = new PdfPCell();
        cell35.setBorderWidth(0.5F);
        cell35.setColspan(3);
        cell35.addElement(blank);
        cell35.addElement(pDate);
        cell35.addElement(blank);
        signTable.addCell(cell35);

        try {
            document.add(signTable);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 卷袋贴生成方法
     *
     * @param document      document
     * @param pdfWriter     pdfWriter
     * @param pdfPackageDto 卷袋贴数据
     */
    private void generatePackagePDF(Document document, PdfWriter pdfWriter, PdfPackageDto pdfPackageDto) {
        try {
            // 空格
            Paragraph blank = new Paragraph(" ");

            if (pdfPackageDto.getTag()) {
                Paragraph para = new Paragraph();
                para.add(new Chunk("订", PdfFillUtils.textFont12));
                para.setAlignment(Element.ALIGN_MIDDLE);//设置对齐方式

                float lly = document.getPageSize().getTop() - 40;
                float ury = document.getPageSize().getTop() - 10;

                Rectangle rects = new Rectangle(15, lly, 50, ury);//文本框位置
//            rects.setBorder(Rectangle.BOX);//显示边框，默认不显示，常量值：LEFT, RIGHT, TOP, BOTTOM，BOX,
                rects.setBorderWidth(1f);//边框线条粗细
                rects.setBorderColor(BaseColor.BLACK);//边框颜色
                pdfWriter.getDirectContent().rectangle(rects);
                ColumnText ct = new ColumnText(pdfWriter.getDirectContent());
                ct.addElement(para);
                ct.setSimpleColumn(rects);
                ct.go();
            }

            // 标题table
            PdfPTable titleTable = PdfFillUtils.createTable(new float[]{80, 20});

            // 条码
            Image code128Image = PdfFillUtils.createBarcode(pdfWriter, pdfPackageDto.getPackageNumber(), false, null, null);
            code128Image.scalePercent(100);
            titleTable.setPaddingTop(1);
            titleTable.addCell(PdfFillUtils.createCell("", null, null, Element.ALIGN_CENTER, 15, 1, 1));
            titleTable.addCell(PdfFillUtils.createCell(code128Image, 30f, Element.ALIGN_CENTER, 15, 1, 1));

            titleTable.addCell(PdfFillUtils.createCell(pdfPackageDto.getTitle(), PdfFillUtils.textFont22, null, Element.ALIGN_CENTER, 15, 1, 2));

            List<Map<String, String>> titlePlate = pdfPackageDto.getTitlePlate();
            for (Map<String, String> stringMap : titlePlate) {
                String value = stringMap.get("value");
                if (StringUtils.isNotBlank(value)) {
                    titleTable.addCell(PdfFillUtils.createCell(value, PdfFillUtils.textFont16, null, Element.ALIGN_CENTER, 15, 1, 2));
                }
            }

            document.add(titleTable);
            document.add(blank);
            document.add(blank);

            // 基础信息表格
            PdfPTable basicTable = PdfFillUtils.createTable(new float[]{1, 23, 3, 73});
            List<Map<String, String>> basicPlate = pdfPackageDto.getBasicPlate();
            for (Map<String, String> stringMap : basicPlate) {
                basicTable.addCell(PdfFillUtils.createCell("", PdfFillUtils.textFont14, 50f, Element.ALIGN_JUSTIFIED_ALL, 0f));
                basicTable.addCell(PdfFillUtils.createCell(stringMap.get("name"), PdfFillUtils.textFont14, 50f, Element.ALIGN_RIGHT, 0f));
                basicTable.addCell(PdfFillUtils.createCell(": ", PdfFillUtils.textFont14, 50f, Element.ALIGN_JUSTIFIED_ALL, 0f));
                basicTable.addCell(PdfFillUtils.createCell(stringMap.get("value"), PdfFillUtils.textFont14, 50f, Element.ALIGN_LEFT, 0f));
            }
            document.add(basicTable);
            document.add(blank);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    private File createFolder(String destUrl) {
        File file = new File(destUrl);
        try {
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
        return file;
    }

    /**
     * 签到表考生签到table表头宽度选择
     *
     * @param basicTemplate 表头字段数量
     */
    private float[] createColumnWidth(BasicTemplate basicTemplate) {
        JSONObject object = JSONObject.parseObject(basicTemplate.getDisplayRange());
        List<CodeNameEnableRate> tableDisplayRanges = JSONObject.parseArray(object.getString("table"), CodeNameEnableRate.class);
        List<Float> rateList = tableDisplayRanges.stream().filter(CodeNameEnableRate::getEnable).map(m -> Float.parseFloat(String.valueOf(m.getRate()))).collect(Collectors.toList());
        float[] columnWidth;
        if (basicTemplate.getDiallel()) {
            columnWidth = new float[rateList.size() * 2];
            for (int i = 0; i < 2; i++) {
                for (int i1 = 0; i1 < rateList.size(); i1++) {
                    columnWidth[rateList.size() * i + i1] = rateList.get(i1) / 2;
                }
            }
        } else {
            columnWidth = new float[rateList.size()];
            for (int i = 0; i < rateList.size(); i++) {
                columnWidth[i] = rateList.get(i);
            }
        }
        return columnWidth;
    }

    /**
     * 根据表格大小，选择字号
     *
     * @param basicTemplate 值
     */
    private Font chooseFont(BasicTemplate basicTemplate) {
        FontSizeEnum fontSize = basicTemplate.getFontSize();
        if (fontSize == null) {
            return PdfFillUtils.textFont9;
        }
        Font font = PdfFillUtils.textFont9;
        switch (fontSize) {
            case SMALL:
                font = PdfFillUtils.textFont9;
                break;
            case MEDIUM:
                font = PdfFillUtils.textFont11;
                break;
            case LARGE:
                font = PdfFillUtils.textFont14;
                break;
            default:
                break;
        }
        return font;
    }

    /**
     * 内部类
     * 添加页眉、页脚
     */
    public static class MyHeaderFooter extends PdfPageEventHelper {
        private String packageCode;

        public MyHeaderFooter(String packageCode) {
            this.packageCode = packageCode;
        }

        // 总页数
        PdfTemplate totalPage;

        // 打开文档时，创建一个总页数的模版
        @Override
        public void onOpenDocument(PdfWriter writer, Document document) {
            PdfContentByte cb = writer.getDirectContent();
            totalPage = cb.createTemplate(30, 16);
        }

        // 一页加载完成触发，写入页眉和页脚
        @Override
        public void onEndPage(PdfWriter writer, Document document) {
            // 添加页眉
            addHeader(writer);
            // 添加页脚
            addFooter(writer);

        }

        private void addHeader(PdfWriter writer) {
            String packageNumber = packageCode.concat(String.valueOf(writer.getPageNumber()));
            PdfPTable table = new PdfPTable(2);
            try {
                table.setTotalWidth(PageSize.A4.getWidth() - 80);
                table.setWidths(new int[]{80, 20});
                table.setLockedWidth(true);
                table.getDefaultCell().setFixedHeight(0f);
//                table.getDefaultCell().setBorder(Rectangle.NO_BORDER);
//                table.getDefaultCell().setBorderWidth(0.5f);

                table.addCell(PdfFillUtils.createCell("", null, null, Element.ALIGN_CENTER, 15, 1, 1));
                table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
                // 条码
                Image code128Image = PdfFillUtils.createBarcode(writer, packageNumber, false, null, null);
                code128Image.scalePercent(100);
                table.addCell(PdfFillUtils.createCellBarCode(code128Image, 30f, Element.ALIGN_RIGHT, 15, 1, 1));
                // 页眉
                table.writeSelectedRows(0, -1, 40, PageSize.A4.getHeight() - 5, writer.getDirectContent());
            } catch (Exception de) {
                throw new ExceptionConverter(de);
            }
        }

        private void addFooter(PdfWriter writer) {
            PdfPTable table = new PdfPTable(2);
            try {
                table.setTotalWidth(PageSize.A4.getWidth() - 80);
                table.setWidths(new int[]{50, 50});
                table.setLockedWidth(true);
                table.getDefaultCell().setFixedHeight(-10f);
                table.getDefaultCell().setBorder(Rectangle.NO_BORDER);
                table.getDefaultCell().setBorderWidth(0.5f);

                table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
                table.addCell(new Paragraph("第" + writer.getPageNumber() + "页   /", PdfFillUtils.textFont8));
                // 总页数
                PdfPCell cell = new PdfPCell(Image.getInstance(totalPage));
                cell.setBorder(Rectangle.NO_BORDER);
                table.addCell(cell);
                // 将页眉写到document中，位置可以指定，指定到下面就是页脚
                // 页眉
//                table.writeSelectedRows(0, -1, 40, PageSize.A4.getHeight() - 10, writer.getDirectContent());
                // 页脚
                table.writeSelectedRows(0, -1, 40, 20, writer.getDirectContent());
            } catch (Exception de) {
                throw new ExceptionConverter(de);
            }
        }

        // 全部完成后，将总页数的pdf模版写到指定位置
        @Override
        public void onCloseDocument(PdfWriter writer, Document document) {
            String text = "共" + (writer.getPageNumber()) + "页";
            ColumnText.showTextAligned(totalPage, Element.ALIGN_LEFT, new Paragraph(text, PdfFillUtils.textFont8), 2, 6, 0);
        }
    }


    /**
     * 测试方法
     *
     * @param args
     */
    public static void main(String[] args) {
        PdfSignDto pdfFillDto = new PdfSignDto();
        pdfFillDto.setTitle("测试签到表");
        pdfFillDto.setPackageNumber("1000004");

        // 基础信息
        List<Map<String, String>> basicPlate = new ArrayList<>();
        Map<String, String> basicMap = new HashMap<>();
        basicMap.put("code", "courseCode");
        basicMap.put("name", "课程代码");
        basicMap.put("value", "高等数学");
        basicPlate.add(basicMap);

        basicMap = new HashMap<>();
        basicMap.put("code", "paperNumber");
        basicMap.put("name", "试卷编号");
        basicMap.put("value", "bh001");
        basicPlate.add(basicMap);

        basicMap = new HashMap<>();
        basicMap.put("code", "examTime");
        basicMap.put("name", "考试时间");
        basicMap.put("value", "2022-09-10 9：00-12：00");
        basicPlate.add(basicMap);

        basicMap = new HashMap<>();
        basicMap.put("code", "examRoom");
        basicMap.put("name", "考试地点");
        basicMap.put("value", "教学楼301");
        basicPlate.add(basicMap);

        basicMap = new HashMap<>();
        basicMap.put("code", "examCount");
        basicMap.put("name", "应考人数");
        basicMap.put("value", "61");
        basicPlate.add(basicMap);

        basicMap = new HashMap<>();
        basicMap.put("code", "actualExamCount");
        basicMap.put("name", "实考人数");
        basicMap.put("value", "");
        basicPlate.add(basicMap);

        pdfFillDto.setBasicPlate(basicPlate);

        // 表头信息
        Map<String, String> studentHeadPlateMap = new LinkedHashMap<>();
        studentHeadPlateMap.put("seq", "序号");
        studentHeadPlateMap.put("studentCode", "学号");
        studentHeadPlateMap.put("studentName", "姓名");
        studentHeadPlateMap.put("className", "班级");
        studentHeadPlateMap.put("studentSign", "签名");
        pdfFillDto.setStudentHeadPlate(studentHeadPlateMap);

        // 考生信息
        List<Map<String, String>> studentPlate = new ArrayList<>();
        for (int i = 0; i < 150; i++) {
            Map<String, String> studentMap = new HashMap<>();
            String seq = String.valueOf(i + 1);
            studentMap.put("seq", seq);
            studentMap.put("studentCode", "20010" + String.format("%03d", i + 1));
            if (i > 10 && i < 20) {
                studentMap.put("studentName", "学生" + String.format("%06d", i + 1));
            } else if (i > 34 && i < 50) {
                studentMap.put("studentName", "学生" + String.format("%010d", i + 1));
            } else {
                studentMap.put("studentName", "学生" + seq);
            }
            studentMap.put("className", "班级1");
            studentMap.put("studentSign", "");
            studentPlate.add(studentMap);
        }
        pdfFillDto.setStudentPlate(studentPlate);

        PdfPackageDto pdfPackageDto = new PdfPackageDto();
        pdfPackageDto.setTitle("测试卷袋贴");
        pdfPackageDto.setPackageNumber("1000004");

        // 基础信息
        List<Map<String, String>> basicPlate1 = new ArrayList<>();
        Map<String, String> basicMap1 = new HashMap<>();
        basicMap1.put("code", "courseCode");
        basicMap1.put("name", "课程代码");
        basicMap1.put("value", "高等数学");
        basicPlate1.add(basicMap1);

        basicMap1 = new HashMap<>();
        basicMap1.put("code", "paperNumber");
        basicMap1.put("name", "试卷编号");
        basicMap1.put("value", "bh001");
        basicPlate1.add(basicMap1);

        basicMap1 = new HashMap<>();
        basicMap1.put("code", "examTime");
        basicMap1.put("name", "考试时间");
        basicMap1.put("value", "2022-09-10 9：00-12：00");
        basicPlate1.add(basicMap1);

        basicMap1 = new HashMap<>();
        basicMap1.put("code", "examRoom");
        basicMap1.put("name", "考试地点");
        basicMap1.put("value", "教学楼301");
        basicPlate1.add(basicMap1);

        basicMap1 = new HashMap<>();
        basicMap1.put("code", "examCount");
        basicMap1.put("name", "应考人数");
        basicMap1.put("value", "61");
        basicPlate1.add(basicMap1);

        pdfPackageDto.setBasicPlate(basicPlate1);

        try {
            CreatePrintPdfUtil createPrintPdfUtil = new CreatePrintPdfUtil();
            createPrintPdfUtil.createSignPdf(pdfFillDto, "/Users/xiaofei/sign.pdf", null);
//            createPrintPdfUtil.createPackagePdf(pdfPackageDto, "D:/package.pdf");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
