package cn.wise.sc.energy.power.plant.business.utils.poi;

import cn.afterturn.easypoi.entity.ImageEntity;
import cn.afterturn.easypoi.util.PoiPublicUtil;
import cn.afterturn.easypoi.word.entity.params.ExcelListEntity;
import cn.afterturn.easypoi.word.parse.excel.ExcelEntityParse;
import cn.afterturn.easypoi.word.parse.excel.ExcelMapParse;
import cn.wise.sc.energy.power.plant.business.constant.Constance;
import cn.wise.sc.energy.power.plant.common.core.exception.ResponseEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static cn.afterturn.easypoi.util.PoiElUtil.EMPTY;
import static cn.afterturn.easypoi.util.PoiElUtil.END_STR;
import static cn.afterturn.easypoi.util.PoiElUtil.FOREACH;
import static cn.afterturn.easypoi.util.PoiElUtil.START_STR;

/**
 * @author shulidong
 * @since 2020/9/20 17:03
 */
public class PoiiUtiil {

    private static final Logger LOGGER = LoggerFactory.getLogger(PoiiUtiil.class);

    private static String defaultTextSource = "reportInfo";

    //读取配置文件
    //text,for,chart三种标签都不获取配置,直接在语句里读取
    public static void paragraph(List<XWPFParagraph> paragraphs, JSONObject ordinal) throws Exception {
        for (XWPFParagraph paragraph : paragraphs) {
            parseThisParagraph(paragraph, ordinal);
        }
    }

    public static void parseThisParagraph(XWPFParagraph paragraph, JSONObject textSource) throws Exception {
        XWPFRun run;
        // 拿到的第一个run,用来set值,可以保存格式
        XWPFRun currentRun = null;
        // 存放当前的text
        String currentText = "";
        String text;
        // 判断是不是已经遇到{{
        Boolean isfinde = false;
        // 存储遇到的run,把他们置空
        List<Integer> runIndex = new ArrayList<Integer>();
        for (int i = 0; i < paragraph.getRuns().size(); i++) {
            run = paragraph.getRuns().get(i);
            text = run.getText(0);
            if (org.apache.commons.lang3.StringUtils.isEmpty(text)) {
                continue;
            } // 如果为空或者""这种这继续循环跳过
            if (isfinde) {
                currentText += text;
                if (currentText.indexOf(START_STR) == -1) {
                    isfinde = false;
                    runIndex.clear();
                } else {
                    runIndex.add(i);
                }
                if (currentText.indexOf(END_STR) != -1) {
                    changeValues(paragraph, currentRun, currentText, runIndex, textSource);
                    currentText = currentText.indexOf("{")!=-1?currentText.substring(currentText.indexOf("{")):"";
                    isfinde = false;
                }
                // 判断是不是开始，考虑单个‘{’的情况
            } else if (text.indexOf(START_STR) >= 0 || text.indexOf("{") >= 0) {
                currentText = text;
                isfinde = true;
                currentRun = run;
            } else {
                currentText = "";
            }
            if (currentText.indexOf(END_STR) != -1) {
                changeValues(paragraph, currentRun, currentText, runIndex, textSource);
                isfinde = false;
            }
        }

    }

    /**
     * 根据条件改变值
     */
    private static void changeValues(XWPFParagraph paragraph, XWPFRun currentRun, String currentText,
                                     List<Integer> runIndex, JSONObject map) throws Exception {
        // 判断是不是迭代输出
        if (currentText.contains(FOREACH) && currentText.startsWith(START_STR)) {
            currentText = currentText.replace(FOREACH, EMPTY).replace(START_STR, EMPTY).replace(END_STR, EMPTY);
            String[] keys = currentText.replaceAll("\\s{1,}", " ").trim().split(" ");
            List list = (List) PoiPublicUtil.getParamsValue(keys[0], map);
            list.forEach(obj -> {
                if (obj instanceof ImageEntity) {
                    currentRun.setText("", 0);
                    ExcelMapParse.addAnImage((ImageEntity) obj, currentRun);
                } else {
                    PoiPublicUtil.setWordText(currentRun, obj.toString());
                }
            });
        } else {
            Object obj = getRealValue(currentText, map);
            // 如果是图片就设置为图片
            if (obj instanceof ImageEntity) {
                currentRun.setText("", 0);
                ExcelMapParse.addAnImage((ImageEntity) obj, currentRun);
            } else {
                currentText = obj.toString();
                PoiPublicUtil.setWordText(currentRun, "".equals(currentText)?"暂未获取":currentText);
            }
        }

        for (int k = 0; k < runIndex.size(); k++) {
            paragraph.getRuns().get(runIndex.get(k)).setText("", 0);
        }
        runIndex.clear();
    }

    public static Object getRealValue(String currentText, JSONObject map) throws Exception {
        String params = "";
        String[] param = currentText.split(Constance.SPLIT);
        if (param.length < 4) {
            ResponseEnum.BUSINESS_ERROR.newException("expression lost something->缺少':'");
        }
        JSONObject textSource;
        if (StringUtils.isEmpty(map.get(param[2]))) {
            textSource = (JSONObject) map.get(defaultTextSource);
        } else {
            textSource = (JSONObject) map.get(param[2]);
        }
        if (textSource == null) {
            ResponseEnum.BUSINESS_ERROR.newException("未找到匹配的解析类");
        }

        String text = StringUtils.isEmpty(textSource.getString(param[3])) ? "" : textSource.getString(param[3]);
        params = currentText.substring(currentText.indexOf("{{") + 2, currentText.indexOf("}}"));
        currentText = currentText.replace("{{" + params + "}}", text);

        return currentText;
    }

    /**
     * {{:table:source:id:col:}}
     *
     * @param tables
     * @param ordinal
     * @param tableAttr
     */
    public static void table(List<XWPFTable> tables, JSONObject ordinal, Map<String, String> tableAttr) {
        for (XWPFTable table : tables) {
            //获取table的头信息 {{:table:source:name:type:}}
            if (table.getText().contains("{{:text")) {
                List<XWPFTableCell> cells = new ArrayList<>();
                for (int i = 0; i < table.getRows().size(); i++) {
                    XWPFTableRow row = table.getRow(i);
                    for (XWPFTableCell cell : row.getTableCells()) {
                        if (cell.getText().contains(":text:")) {
                            cells.add(cell);
                        }
                    }
                }
                for (int ii = 0; ii < cells.size(); ii++) {
                    XWPFTableCell cell = cells.get(ii);
                    String[] innCellParams = cell.getText().split(":");
                    JSONObject textSource;
                    if (StringUtils.isEmpty(ordinal.get(innCellParams[2]))) {
                        textSource = (JSONObject) ordinal.get(defaultTextSource);
                    } else {
                        textSource = (JSONObject) ordinal.get(innCellParams[2]);
                    }
                    //清除掉已有的paragraph
                    cell.removeParagraph(0);
                    cell.addParagraph();

                    XWPFTableRow row = table.getRow(ii);
                }
            }
            if (table.getText().contains("{{:table")) {
                String[] tab = table.getText().split(Constance.SPLIT);
                int originalRowNum = table.getRows().size();
                JSONArray tableList = ordinal.getJSONArray(tab[2]);
                if (tableList == null || tableList.isEmpty()) {
                    continue;
                }
                //表头字段
                if (tableAttr.get(tab[3]) == null) {
                    LOGGER.error(tab[3] + "");
                }
                String[] params = tableAttr.get(tab[3]).split(splitBySymbol(tableAttr.get(tab[3])));
                //表格类型是竖向写还是横向写,不写的话默认横向
                String type = "row";
                LOGGER.info(tab[3] + "开始填充");
                if (!StringUtils.isEmpty(tab[4])) {
                    type = tab[4];
                }
                for (int k = 0; k < tableList.size(); k++) {
                    JSONObject sourceObj = tableList.getJSONObject(k);
                    sourceObj.put("blankStr", "");
                    //竖向写表格
                    if ("col".equals(type)) {
                        for (int i = 0; i < table.getRows().size(); i++) {
                            XWPFTableRow row = table.getRow(i);
                            if (i > 0) {
                                row.setHeight(300);
                            }
                            XWPFTableCell cell = row.createCell();
                        }
                    }
                    //横向写表格
                    if ("row".equals(type)) {
                        table.createRow();
                        XWPFTableRow row = table.getRow(originalRowNum + k);
                        row.setHeight(300);
                        for (int i = 0; i < row.getTableCells().size(); i++) {
                            XWPFTableCell cell = row.getCell(i);
                        }
                    }
                }
                //竖向表格动态设置列宽
                if ("col".equals(type)) {
                    int colLength = tableList.size() + Integer.parseInt(tab[5]);
                    TableUtil.setTableWidth(table, POIConstance.A4_TABLE_TENDER_WIDTH);
                    setTableGridCol(table, colLength, POIConstance.A4_TABLE_TENDER_WIDTH);
                }
                //清除掉表格头标记
                XWPFTableCell cell0 = table.getRow(0).getCell(0);
                cell0.getParagraphs().get(0).getRuns().get(0).setText("", 0);
            }
        }
    }

    /**
     * {{:table:source:id:col:}}
     *
     * @param tables
     * @param ordinal
     */
    public static void table(List<XWPFTable> tables, JSONObject ordinal) throws Exception {
        for (XWPFTable table : tables) {
            //获取table的头信息 {{:table:source:name:type:}}
            if (table.getText().contains("{{:text")) {
                List<XWPFTableCell> cells = new ArrayList<>();
                for (int i = 0; i < table.getRows().size(); i++) {
                    XWPFTableRow row = table.getRow(i);
                    for (XWPFTableCell cell : row.getTableCells()) {
                        if (cell.getText().contains(":text:")) {
                            cells.add(cell);
                        }
                    }
                }
                for (int ii = 0; ii < cells.size(); ii++) {
                    XWPFTableCell cell = cells.get(ii);

                    XWPFTableRow row = table.getRow(ii);
                    setCellRun(ordinal, cell);
                }
            }
        }
    }

    /**
     * 设置cell的run的文本样式
     *
     * @param sourceObj
     * @param cell
     */
    private static void setCellRun(JSONObject sourceObj, XWPFTableCell cell) throws Exception {
        XWPFParagraph paragraph = cell.getParagraphs().get(0);
        paragraph.setAlignment(ParagraphAlignment.CENTER);
        parseThisParagraph(paragraph,sourceObj);
        cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
    }

    /**
     * @Description: 设置表格列宽
     */
    private static void setTableGridCol(XWPFTable table, int colLength, int tableWidth) {
        CTTbl ttbl = table.getCTTbl();
        CTTblGrid tblGrid = ttbl.getTblGrid() != null ? ttbl.getTblGrid() : ttbl.addNewTblGrid();
        for (int j = 0; j < colLength; j++) {
            CTTblGridCol gridCol = tblGrid.addNewGridCol();
            gridCol.setW(new BigInteger(String.valueOf(tableWidth / colLength)));
        }
    }

    //分隔符语法扩展 支持 |,&,*,%,@,!,$,~,- 不能用:
    private static String splitBySymbol(String str) {
        List<String> partations = new ArrayList<>();
        Pattern p = Pattern.compile("(\\|)|\\&|\\*|\\%|\\@|\\!|\\$|\\~|\\-");
        Matcher m = p.matcher(str);
        boolean unContainsSymbol = true;
        String symbol = ":";
        if (m.find()) {
            symbol = m.group();
        }
        return "\\" + symbol;
    }

    public static void parseThisTable(List<XWPFTable> tables, Map<String, Object> map) throws Exception {
        for (XWPFTable table : tables) {
            for(int i = 0; i < table.getNumberOfRows(); ++i) {
                XWPFTableRow row = table.getRow(i);
                List<XWPFTableCell> cells = row.getTableCells();
                Object listobj = checkThisTableIsNeedIterator((XWPFTableCell)cells.get(0), map);
                if (listobj == null) {
                    parseThisRow(cells, map);
                } else if (listobj instanceof ExcelListEntity) {
                    (new ExcelEntityParse()).parseNextRowAndAddRow(table, i, (ExcelListEntity)listobj);
                    i = i + ((ExcelListEntity)listobj).getList().size() - 1;
                } else {
                    ExcelMapParse.parseNextRowAndAddRow(table, i, (List)listobj);
                    i = i + ((List)listobj).size() - 1;
                }
            }
        }
    }
    private static void parseThisRow(List<XWPFTableCell> cells, Map<String, Object> map) throws Exception {
        Iterator var3 = cells.iterator();

        while(var3.hasNext()) {
            XWPFTableCell cell = (XWPFTableCell)var3.next();
            parseAllParagraphic(cell.getParagraphs(), map);
        }

    }
    private static void parseAllParagraphic(List<XWPFParagraph> paragraphs, Map<String, Object> map) throws Exception {
        for(int i = 0; i < paragraphs.size(); ++i) {
            XWPFParagraph paragraph = (XWPFParagraph)paragraphs.get(i);
            if (paragraph.getText().indexOf("{{") != -1) {
                parseThisParagraph(paragraph, map);
            }
        }

    }

    public static void main(String[] args) {
        String p = "fdfdf}}";
        String current =p.indexOf("{")!=-1? p.substring(p.indexOf("{")):"";
        System.out.println(current);

    }
    private static void parseThisParagraph(XWPFParagraph paragraph, Map<String, Object> map) throws Exception {
        XWPFRun currentRun = null;
        String currentText = "";
        Boolean isfinde = false;
        List<Integer> runIndex = new ArrayList();

        for(int i = 0; i < paragraph.getRuns().size(); ++i) {
            XWPFRun run = (XWPFRun)paragraph.getRuns().get(i);
            String text = run.getText(0);
            if (!org.apache.commons.lang3.StringUtils.isEmpty(text)) {
                if (isfinde) {
                    currentText = currentText + text;
                    if (currentText.indexOf("{{") == -1) {
                        isfinde = false;
                        runIndex.clear();
                    } else {
                        runIndex.add(i);
                    }

                    if (currentText.indexOf("}}") != -1) {
                        changeValues(paragraph, currentRun, currentText, runIndex, map);
                        //考虑有 “:adfd}}{”的情况
                        currentText = currentText.indexOf("{")!=-1?currentText.substring(currentText.indexOf("{")):"";
                        isfinde = false;
                    }
                } else if (text.indexOf("{{") >= 0 || text.indexOf("{")>=0) {
                    currentText = text;
                    isfinde = true;
                    currentRun = run;
                } else {
                    currentText = "";
                }

                if (currentText.indexOf("}}") != -1) {
                    changeValues(paragraph, currentRun, currentText, runIndex, map);
                    isfinde = false;
                }
            }
        }

    }
    private static void changeValues(XWPFParagraph paragraph, XWPFRun currentRun, String currentText, List<Integer> runIndex, Map<String, Object> map) throws Exception {
        Object obj = PoiPublicUtil.getRealValue(currentText, map);
        if (obj instanceof ImageEntity) {
            currentRun.setText("", 0);
            ExcelMapParse.addAnImage((ImageEntity)obj, currentRun);
        } else {
            currentText = obj.toString();
            PoiPublicUtil.setWordText(currentRun, currentText);
        }

        for(int k = 0; k < runIndex.size(); ++k) {
            ((XWPFRun)paragraph.getRuns().get((Integer)runIndex.get(k))).setText("", 0);
        }

        runIndex.clear();
    }

    private static Object checkThisTableIsNeedIterator(XWPFTableCell cell, Map<String, Object> map) throws Exception {
        String text = cell.getText().trim();
        if (text != null && text.contains("fe:") && text.startsWith("{{")) {
            text = text.replace("!fe:", "").replace("$fe:", "").replace("fe:", "").replace("{{", "");
            String[] keys = text.replaceAll("\\s{1,}", " ").trim().split(" ");
            return PoiPublicUtil.getParamsValue(keys[0], map);
        } else {
            return null;
        }
    }

}
