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

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
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.XWPFChart;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import java.io.InputStream;
import java.util.HashMap;
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 WordChartParser extends WordContentParser {

    private List<ChartReplace> chartReplaces;

    public WordChartParser(InputStream in, List<ChartReplace> chartReplaces) {
        super(in);
        this.chartReplaces = chartReplaces;
    }

    public WordChartParser(XWPFDocument doc, List<ChartReplace> chartReplaces) {
        super(doc);
        this.chartReplaces = chartReplaces;
    }

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

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

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

    @Setter
    @Getter
    public static class ChartReplace {
        //图表标题
        private String chartTitle;
        //x分类轴标题
        private String categoryAxisTitle;
        //y值轴标题
        private String valueAxesTitle;
        //图表在word文档中的xml名称，格式 /word/charts/chart1.xml | /word/charts/chart2.xml
//        private String chartXmlName;
        //图表在模板中的下标，从1开始
        private int index;
        //图表分类名称
        private String[] categoryNames;

        private String[] categoryNames1;
        //图表数据行值
        private List<LineValue> lineValues;
    }

    @Setter
    @Getter
    public static class LineValue {
        //图表数据名称
        private String lineName;
        //图表数据行值
        private Number[] lineValue;
        //设置标记样式
        private MarkerStyle markerStyle;

        public LineValue() {
            // 设置标记样式
            markerStyle = MarkerStyle.NONE;
        }

    }

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

        List<XWPFChart> charts = getDoc().getCharts();
        if (CollectionUtils.isEmpty(charts)) {
            throw new RuntimeException(ERR_MSG_TEMPLATE_CHART_NOT_EXIST.replace("${name}", ""));
        }

        Map<Integer, XWPFChart> templateChartMap = new HashMap<>();
        for (int i = 1, size = charts.size(); i <= size; i++) {
            String key = charts.get(i - 1).toString().replaceAll("Name: ", "")
                    .replaceAll(" - Content Type: application/vnd\\.openxmlformats-officedocument\\.drawingml\\.chart\\+xml", "").trim();
            key = key.replace("/word/charts/chart", "").replace(".xml", "");
            templateChartMap.put(Integer.valueOf(key), charts.get(i - 1));
        }

        chartReplaces.forEach(lineChartReplace -> {
            List<LineValue> lineValues = lineChartReplace.getLineValues();
            if (CollectionUtils.isEmpty(lineValues)) {
                throw new RuntimeException(ERR_MSG_PARAM_NOT_INITIALIZED);
            }
            //校验元素个数是否一致
            int dataLength = lineChartReplace.getCategoryNames().length;
            for (int i = 0, size = lineValues.size(); i < size; i++) {
                if (lineValues.get(i).getLineValue().length != dataLength) {
                    throw new RuntimeException(ERR_MSG_ROW_ELEMENT_MISMATCH.replace("${index}", String.valueOf(i)));
                }
            }
            //校验图表是否存在
            XWPFChart templateChart = templateChartMap.get(lineChartReplace.getIndex());
            if (Objects.isNull(templateChart)) {
                throw new RuntimeException(ERR_MSG_TEMPLATE_CHART_NOT_EXIST.replace("${index}", String.valueOf(lineChartReplace.getIndex())));
            }
        });

        //逐个图表进行内容替换
        chartReplaces.forEach(lineChartReplace -> {
            XWPFChart templateChart = templateChartMap.get(lineChartReplace.getIndex());
            templateChart.setTitleText(lineChartReplace.getChartTitle());//图表标题
            XDDFCategoryDataSource categoryDataSource = XDDFDataSourcesFactory.fromArray(lineChartReplace.getCategoryNames1());//分类名称
            templateChart.getChartSeries().forEach(chartData -> {
                if (Objects.nonNull(chartData.getCategoryAxis())) {
                    chartData.getCategoryAxis().setTitle(lineChartReplace.getCategoryAxisTitle());//x轴标题
                }
                if (Objects.nonNull(chartData.getValueAxes())) {
                    chartData.getValueAxes().forEach(axis -> {
                        axis.setTitle(lineChartReplace.getValueAxesTitle());//y轴标题
                    });
                }
                //删除模板自带的图表数据
                for (int i = 0, count = chartData.getSeriesCount(); i < count; i++) {
                    chartData.removeSeries(0);
                }

                //渲染数据
                lineChartReplace.getLineValues().forEach(lineValue -> {
                    XDDFNumericalDataSource<Number> values = XDDFDataSourcesFactory.fromArray(lineValue.getLineValue());
                    // 图表加载数据
                    XDDFChartData.Series series = chartData.addSeries(categoryDataSource, values);
                    // 图表例标题
                    series.setTitle(lineValue.getLineName(), null);
                    // 设置标记样式
                    setMarkerStyle(series, lineValue);
                });

                // 绘制
                templateChart.plot(chartData);

            });
        });

        return getDoc();
    }

    private void setMarkerStyle(XDDFChartData.Series series, LineValue lineValue) {
        if (series instanceof XDDFLineChartData.Series) {
            ((XDDFLineChartData.Series)series).setMarkerStyle(lineValue.getMarkerStyle());
        }
        //其它图表
    }


    public void generateChart() {
        List<XWPFChart> charts = getDoc().getCharts();

        for (int i = 0; i < charts.size() && i < chartReplaces.size(); i++) {
            XWPFChart chart = charts.get(i);
            ChartReplace chartReplace = chartReplaces.get(i);

            final List<XDDFChartData> datas = chart.getChartSeries();//不知道这个ChartSeries代表什么意思
            final XDDFLineChartData line = (XDDFLineChartData) datas.get(0);//这里一般获取第一个,我们这里是折线图就是XDDFLineChartData
            final int numOfPoints = chartReplace.getCategoryNames1().length;

            final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
            final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(chartReplace.getCategoryNames1(), categoryDataRange, 0);
            for (int j = 0; j < chartReplace.getLineValues().size(); j++) {
                final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, j + 1, j + 1));
                Number[] value = chartReplace.getLineValues().get(j).getLineValue();
                final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(value, valuesDataRange, j + 1);
                XDDFChartData.Series ser;//图表中的系列
                ser = line.getSeries().get(j);
                ser.replaceData(categoriesData, valuesData);
                CellReference cellReference = chart.setSheetTitle(chartReplace.getLineValues().get(j).lineName, 1);//修改系列标题
                ser.setTitle(chartReplace.getLineValues().get(j).lineName, cellReference);
            }
            chart.plot(line);
            chart.setTitleText(chartReplace.getChartTitle());//折线图标题
            chart.setTitleOverlay(false);
        }
    }
}
