package com.limap.common.utils.poi.parser;

import com.limap.common.utils.StringUtils;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xwpf.usermodel.*;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <p>Word表格解析器</p>
 *
 * @author Allen Yang
 * @datetime 2021/11/18 14:53
 */
@Setter
@Getter
public class WordTableParser extends WordContentParser {

    private Map<String, String> textReplaceMap;

    private List<TableReplace> tableReplaces;

    public WordTableParser(InputStream in, List<TableReplace> tableReplaces) {
        super(in);
        this.tableReplaces = tableReplaces;
    }

    public WordTableParser(XWPFDocument doc, List<TableReplace> tableReplaces) {
        super(doc);
        this.tableReplaces = tableReplaces;
    }

    public WordTableParser(XWPFDocument doc, List<TableReplace> tableReplaces, Map<String, String> textReplaceMap) {
        super(doc);
        this.textReplaceMap = textReplaceMap;
        this.tableReplaces = tableReplaces;
    }

    public WordTableParser(InputStream in) {
        super(in);
    }

    public WordTableParser(XWPFDocument doc) {
        super(doc);
    }

    public WordTableParser(String path) {
        super(path);
    }

    @Setter
    @Getter
    public static class TableReplace {
        //表格在word文档中的下标
        private int index;
        //数据开始渲染下标
        private int startIndex;
        //数据行值
        private List<Object[]> rowValues;
        //数据行值是否粗体字
        private List<Boolean[]> rowBolds;
        //是否覆盖单元格已有文字
        private boolean coverExisting;
        //是否删除单元格已有的图片
        private boolean removePicture;
        public TableReplace() {
            this.coverExisting = true;
            this.removePicture = false;
        }

        public void setRowValues(List<Object[]> rowValues) {
            this.rowValues = rowValues;
            if (!CollectionUtils.isEmpty(rowValues)) {
                this.rowBolds = new ArrayList<>();
                rowValues.forEach(values -> {
                    Boolean[] booleans = new Boolean[values.length];
                    for (int i = 0, len = booleans.length; i < len; i++) {
                        booleans[i] = false;
                        this.rowBolds.add(booleans);
                    }
                });

            }
        }
    }

    @Override
    public XWPFDocument replace() {
        if (Objects.isNull(getDoc())) {
            throw new RuntimeException(ERR_MSG_DOC_NOT_LOADED);
        }
        if (CollectionUtils.isEmpty(tableReplaces)) {
            throw new RuntimeException(ERR_MSG_PARAM_NOT_INITIALIZED);
        }

        tableReplaces.forEach(tableReplace -> {
            if (CollectionUtils.isEmpty(tableReplace.getRowValues())) {
                throw new RuntimeException(ERR_MSG_PARAM_NOT_INITIALIZED);
            }
            //校验元素个数是否一致
            int dataLength = tableReplace.getRowValues().get(0).length;
            for (int i = 0, size = tableReplace.getRowValues().size(); i < size; i++) {
                if (tableReplace.getRowValues().get(i).length != dataLength) {
                    throw new RuntimeException(ERR_MSG_ROW_ELEMENT_MISMATCH.replace("${index}", String.valueOf(i)));
                }
            }
            //校验表格是否存在
            XWPFTable templateTable = getDoc().getTableArray(tableReplace.getIndex());
            if (Objects.isNull(templateTable)) {
                throw new RuntimeException(ERR_MSG_TABLE_NOT_EXIST.replace("${index}", String.valueOf(tableReplace.getIndex())));
            }
            //校验元素个数是否和模板表格单元格个数一致
            if (templateTable.getRows().get(templateTable.getNumberOfRows() - 1).getTableCells().size() != dataLength) {
                throw new RuntimeException(ERR_MSG_CELLS_NOT_UNANIMOUS.replace("${index}", String.valueOf(tableReplace.getIndex())));
            }
            int templateRowCount = templateTable.getNumberOfRows();//模板表格行数
            int valueRowCount = tableReplace.getRowValues().size();//值行数
            int newRowCount = valueRowCount - templateRowCount + tableReplace.getStartIndex();
            if (newRowCount > 0) {//新增行
                for (int i = 0; i < newRowCount; i++) {
                    insertNewTableRow(templateTable, templateTable.getNumberOfRows() - 1, templateTable.getNumberOfRows());
                }
            } else if (newRowCount < 0) {//删除行
                for (int i = 0; i < (-newRowCount); i++) {
                    templateTable.removeRow(templateTable.getNumberOfRows() - 1);
                }
            }
        });

        //逐个表格进行单元格内容替换
        tableReplaces.forEach(tableReplace -> {
            XWPFTable templateTable = getDoc().getTableArray(tableReplace.getIndex());
            for (int i = 0, size = tableReplace.getRowValues().size(); i < size; i++) {
                Object[] values = tableReplace.getRowValues().get(i);
                Boolean[] bolds = tableReplace.getRowBolds().get(i);
                for (int j = 0, len = values.length; j < len; j++) {

                    //单元格赋值
                    XWPFTableCell cell = templateTable.getRow(tableReplace.getStartIndex() + i).getCell(j);
                    if (Objects.nonNull(cell)) {
                        long picCount = cell.getParagraphs().stream().filter(o -> o.getRuns().stream().mapToInt(r -> r.getEmbeddedPictures().size()).sum() > 0).count();
                        if (StringUtils.isEmpty(cell.getText()) && picCount == 0) {
                            //cell.setText(String.valueOf(values[j]));
                            if (CollectionUtils.isEmpty(cell.getParagraphs())) {
                                XWPFParagraph xwpfParagraph = cell.addParagraph();
                                XWPFRun xwpfRun = xwpfParagraph.createRun();
                                xwpfRun.setText(String.valueOf(values[j]));
                                xwpfRun.setBold(bolds[j]);
                                xwpfParagraph.addRun(xwpfRun);
                                cell.setParagraph(xwpfParagraph);
                            } else {
                                int finalJ = j;
                                cell.getParagraphs().forEach(xwpfParagraph -> {
                                    List<XWPFRun> runs = xwpfParagraph.getRuns();
                                    if (CollectionUtils.isEmpty(runs)) {
                                        XWPFRun xwpfRun = xwpfParagraph.createRun();
                                        xwpfRun.setText(String.valueOf(values[finalJ]));
                                        xwpfRun.setBold(bolds[finalJ]);
                                        xwpfParagraph.addRun(xwpfRun);
                                    } else {
                                        runs.forEach(run -> {
                                            run.setText((String.valueOf(values[finalJ])), 0);
                                            run.setBold(bolds[finalJ]);
                                        });
                                    }

                                });
                            }
                        } else {
                            if (tableReplace.isRemovePicture()) {//删除图片
                                int finalJ = j;
                                cell.getParagraphs().forEach(xwpfParagraph -> {
                                    List<XWPFRun> runs = xwpfParagraph.getRuns();
                                    for (int k = 0, size2 = runs.size(); k < size2; k++) {
                                        if (CollectionUtils.isNotEmpty(runs.get(k).getEmbeddedPictures())) {
                                            xwpfParagraph.removeRun(k);
                                            XWPFRun xwpfRun = xwpfParagraph.createRun();
                                            xwpfRun.setText(String.valueOf(values[finalJ]), 0);
                                            xwpfRun.setBold(bolds[finalJ]);
                                            xwpfParagraph.addRun(xwpfRun);
                                        } else {
                                            runs.get(k).setText(String.valueOf(values[finalJ]), 0);
                                            runs.get(k).setBold(bolds[finalJ]);
                                        }
                                    }
                                });

                            }

                            if (tableReplace.isCoverExisting()) {//覆盖文字
                                int finalJ = j;
                                cell.getParagraphs().forEach(xwpfParagraph -> {
                                    List<XWPFRun> runs = xwpfParagraph.getRuns();
                                    runs.forEach(run -> {
                                        run.setText(String.valueOf(values[finalJ]), 0);
                                    });
                                });
                            }
                        }

                    }

                }
            }
        });

        if (!MapUtils.isEmpty(textReplaceMap)) {//文本替换
            getDoc().getTables().forEach(templateTable -> {
                templateTable.getRows().forEach(row -> {
                    row.getTableCells().forEach(cell2 -> {
                        if (!Objects.isNull(cell2) && !StringUtils.isEmpty(cell2.getText())) {
                            cell2.getParagraphs().forEach(xwpfParagraph -> {
                                List<XWPFRun> runs = xwpfParagraph.getRuns();
                                runs.forEach(run -> {
                                    String str = run.getText(run.getTextPosition()); //获取run中的字符串
                                    if (StringUtils.isNotEmpty(str)) {
                                        for (Map.Entry<String, String> entry: textReplaceMap.entrySet()) {
                                            str = str.replace(entry.getKey(), entry.getValue());
                                        }
                                    }
                                    run.setText(str, 0);
                                });
                            });
                        }
                    });
                });
            });
        }

        return getDoc();
    }

    /**
     * 在word表格中指定位置插入一行，并将某一行的样式复制到新增行
     * @param table
     * @param copyRowIndex 需要复制的行位置
     * @param newRowIndex 需要新增一行的位置
     */
    private void insertNewTableRow(XWPFTable table, int copyRowIndex, int newRowIndex) {
        // 在表格中指定的位置新增一行
        XWPFTableRow targetRow = table.insertNewTableRow(newRowIndex);
        // 获取需要复制行对象
        XWPFTableRow copyRow = table.getRow(copyRowIndex);
        //复制行对象
        targetRow.getCtRow().setTrPr(copyRow.getCtRow().getTrPr());
        //或许需要复制的行的列
        List<XWPFTableCell> copyCells = copyRow.getTableCells();

        copyCells.forEach(copyCell -> {
            //复制列对象
            XWPFTableCell targetCell = targetRow.addNewTableCell();
            targetCell.getCTTc().setTcPr(copyCell.getCTTc().getTcPr());
            if (CollectionUtils.isNotEmpty(copyCell.getParagraphs())) {
                targetCell.getParagraphs().get(0).getCTP().setPPr(copyCell.getParagraphs().get(0).getCTP().getPPr());
                if (CollectionUtils.isNotEmpty(copyCell.getParagraphs().get(0).getRuns())) {
                    XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();
                    cellR.setBold(copyCell.getParagraphs().get(0).getRuns().get(0).isBold());
                }
            }
        });

    }




    public static void generateChart(XWPFChart chart, String[] series, String[] categories, List<Number[]> values) {
        String chartTitle = "收运量统计图";
        final List<XDDFChartData> data = chart.getChartSeries();//不知道这个ChartSeries代表什么意思
        final XDDFLineChartData line = (XDDFLineChartData) data.get(0);//这里一般获取第一个,我们这里是折线图就是XDDFLineChartData

        final int numOfPoints = categories.length;

        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));

        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
        for (int i = 0; i < values.size(); i++) {
            final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, i + 1, i + 1));
            Number[] value = values.get(i);
            final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(value, valuesDataRange, i + 1);
            XDDFChartData.Series ser;//图表中的系列
            ser = line.getSeries().get(i);
            ser.replaceData(categoriesData, valuesData);
            CellReference cellReference = chart.setSheetTitle(series[i], 1);//修改系列标题
            ser.setTitle(series[i], cellReference);
        }

        chart.plot(line);
        chart.setTitleText(chartTitle);//折线图标题
        chart.setTitleOverlay(false);
    }
}
