package cn.iocoder.lyzsys.module.tjt.service.report.builder;

import lombok.Data;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

@Component
public class ProjectLeadQuarterOutputExcelBuilder extends AbstractProjectOutputExcelBuilder {

    private static final String SHEET1_NAME = "工作量分配";
    private static final String SHEET2_NAME = "季度考核产值";
    private static final String SHEET1_TITLE = "项目经理/专业负责人人员工作量分配";
    private static final String SHEET2_TITLE = "项目经理/工程负责人年度/季度项目考核产值";
    private static final String DEFAULT_PROJECT_MANAGER_HEADER = "项目经理人员";
    private static final String DEFAULT_ENGINEERING_HEADER = "工程负责人人员";
    private static final String DEFAULT_CENTER_SIGNER = "设计中心相关负责人（签名）：";
    private static final String DEFAULT_PROJECT_SIGNER = "项目经理/工程负责人（签名）：";
    private static final List<String> OUTPUT_TYPE_ORDER = Arrays.asList(
            "六大专业考核产值",
            "专项分包产值",
            "源头合作分包产值",
            "内部协作产值",
            "其他产值"
    );

    public Workbook build(ExportData data) {
        Workbook workbook = createWorkbook();
        buildSheet1(workbook, data);
        buildSheet2(workbook, data);
        return workbook;
    }

    private void buildSheet1(Workbook workbook, ExportData data) {
        Sheet sheet = createSheet(workbook, SHEET1_NAME, SHEET1_NAME);
        setColumnWidths(sheet, 8, 26, 18, 24, 20, 20);

        CellStyle titleStyle = createTitleStyle(workbook);
        CellStyle baseHeaderStyle = createHeaderStyle(workbook);
        CellStyle headerStyle = createDerivedStyle(workbook, baseHeaderStyle,
                IndexedColors.LEMON_CHIFFON, HorizontalAlignment.CENTER, true, (short) 10);
        CellStyle cellStyle = createDerivedStyle(workbook, createCellStyle(workbook),
                null, HorizontalAlignment.CENTER, false, (short) 10);
        CellStyle leftCellStyle = createDerivedStyle(workbook, cellStyle,
                null, HorizontalAlignment.LEFT, false, (short) 10);

        int rowIndex = 0;
        rowIndex = writeMergedTitleRow(sheet, rowIndex, SHEET1_TITLE, titleStyle, 5);
        rowIndex = buildSheet1Header(sheet, rowIndex, data, headerStyle);

        List<LeadQuarterRow> rows = resolveDetailRows(data);
        int bodyStartRow = rowIndex;
        for (LeadQuarterRow rowData : rows) {
            writeSheet1DetailRow(sheet, rowIndex++, data, rowData, cellStyle, leftCellStyle);
        }

        mergeProjectNameColumn(sheet, bodyStartRow, rowIndex - 1, data, cellStyle);
        mergeOutputTypeColumn(sheet, bodyStartRow, rows, cellStyle);
    }

    private void buildSheet2(Workbook workbook, ExportData data) {
        Sheet sheet = createSheet(workbook, SHEET2_NAME, SHEET2_NAME);
        setColumnWidths(sheet, 8, 26, 18, 24, 12, 12, 12, 12, 14, 12, 12, 12, 12, 14);

        CellStyle baseHeaderStyle = createHeaderStyle(workbook);
        CellStyle headerStyle = createDerivedStyle(workbook, baseHeaderStyle,
                IndexedColors.LEMON_CHIFFON, HorizontalAlignment.CENTER, true, (short) 10);
        CellStyle subtotalStyle = createDerivedStyle(workbook, baseHeaderStyle,
                IndexedColors.LEMON_CHIFFON, HorizontalAlignment.CENTER, true, (short) 10);
        CellStyle cellStyle = createDerivedStyle(workbook, createCellStyle(workbook),
                null, HorizontalAlignment.CENTER, false, (short) 10);
        CellStyle leftCellStyle = createDerivedStyle(workbook, cellStyle,
                null, HorizontalAlignment.LEFT, false, (short) 10);
        CellStyle signatureStyle = createDerivedStyle(workbook, createInfoStyle(workbook),
                null, HorizontalAlignment.LEFT, false, (short) 10);

        int rowIndex = 0;
        rowIndex = buildSheet2Header(sheet, rowIndex, data, headerStyle);

        List<LeadQuarterRow> rows = resolveSheet2Rows(data);
        int bodyStartRow = rowIndex;
        for (LeadQuarterRow rowData : rows) {
            if (Boolean.TRUE.equals(rowData.getSubtotalRow())) {
                writeSheet2SubtotalRow(sheet, rowIndex++, rowData, subtotalStyle);
                continue;
            }
            writeSheet2DetailRow(sheet, rowIndex++, data, rowData, cellStyle, leftCellStyle);
        }

        mergeProjectNameColumn(sheet, bodyStartRow, rowIndex - 1, data, cellStyle);
        mergeOutputTypeColumn(sheet, bodyStartRow, rows, cellStyle);
        writeSheet2SignatureRow(sheet, rowIndex, data, signatureStyle);
    }

    private int buildSheet1Header(Sheet sheet, int rowIndex, ExportData data, CellStyle headerStyle) {
        int firstRow = rowIndex;
        sheet.createRow(firstRow);
        sheet.createRow(firstRow + 1);

        setMergedRegionText(sheet, firstRow, firstRow + 1, 0, 0, "序号", headerStyle);
        setMergedRegionText(sheet, firstRow, firstRow + 1, 1, 1, "项目名称", headerStyle);
        setMergedRegionText(sheet, firstRow, firstRow, 2, 3, "类别", headerStyle);
        setText(sheet.getRow(firstRow + 1), 2, "产值类型", headerStyle);
        setText(sheet.getRow(firstRow + 1), 3, "设计内容", headerStyle);
        setText(sheet.getRow(firstRow), 4,
                defaultLabel(resolveProjectManagerNames(data), DEFAULT_PROJECT_MANAGER_HEADER), headerStyle);
        setText(sheet.getRow(firstRow), 5,
                defaultLabel(resolveEngineeringPrincipalNames(data), DEFAULT_ENGINEERING_HEADER), headerStyle);
        setText(sheet.getRow(firstRow + 1), 4, "工作比例", headerStyle);
        setText(sheet.getRow(firstRow + 1), 5, "工作比例", headerStyle);
        return rowIndex + 2;
    }

    private int buildSheet2Header(Sheet sheet, int rowIndex, ExportData data, CellStyle headerStyle) {
        int firstRow = rowIndex;
        sheet.createRow(firstRow);
        sheet.createRow(firstRow + 1);
        sheet.createRow(firstRow + 2);

        setMergedRegionText(sheet, firstRow, firstRow + 2, 0, 0, "序号", headerStyle);
        setMergedRegionText(sheet, firstRow, firstRow + 2, 1, 1, "项目名称", headerStyle);
        setMergedRegionText(sheet, firstRow, firstRow + 1, 2, 3, "类别", headerStyle);
        setText(sheet.getRow(firstRow + 2), 2, "产值类型", headerStyle);
        setText(sheet.getRow(firstRow + 2), 3, "设计内容", headerStyle);

        setMergedRegionText(sheet, firstRow, firstRow, 4, 13, SHEET2_TITLE, headerStyle);
        setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 4, 8,
                defaultLabel(resolveProjectManagerNames(data), DEFAULT_PROJECT_MANAGER_HEADER), headerStyle);
        setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 9, 13,
                defaultLabel(resolveEngineeringPrincipalNames(data), DEFAULT_ENGINEERING_HEADER), headerStyle);
        setText(sheet.getRow(firstRow + 2), 4, "一季度", headerStyle);
        setText(sheet.getRow(firstRow + 2), 5, "二季度", headerStyle);
        setText(sheet.getRow(firstRow + 2), 6, "三季度", headerStyle);
        setText(sheet.getRow(firstRow + 2), 7, "四季度", headerStyle);
        setText(sheet.getRow(firstRow + 2), 8, "本年度小计", headerStyle);
        setText(sheet.getRow(firstRow + 2), 9, "一季度", headerStyle);
        setText(sheet.getRow(firstRow + 2), 10, "二季度", headerStyle);
        setText(sheet.getRow(firstRow + 2), 11, "三季度", headerStyle);
        setText(sheet.getRow(firstRow + 2), 12, "四季度", headerStyle);
        setText(sheet.getRow(firstRow + 2), 13, "本年度小计", headerStyle);
        return rowIndex + 3;
    }

    private void writeSheet1DetailRow(Sheet sheet, int rowIndex, ExportData data, LeadQuarterRow rowData,
                                      CellStyle cellStyle, CellStyle leftCellStyle) {
        Row row = sheet.createRow(rowIndex);
        setText(row, 0, rowData.getSerialNo(), cellStyle);
        setText(row, 1, safeText(data.getProjectName()), cellStyle);
        setText(row, 2, safeText(rowData.getOutputType()), cellStyle);
        setText(row, 3, safeText(rowData.getDesignContent()), leftCellStyle);
        setText(row, 4, percentTextOrBlank(rowData.getProjectManagerRatio()), cellStyle);
        setText(row, 5, percentTextOrBlank(rowData.getEngineeringPrincipalRatio()), cellStyle);
    }

    private void writeSheet2DetailRow(Sheet sheet, int rowIndex, ExportData data, LeadQuarterRow rowData,
                                      CellStyle cellStyle, CellStyle leftCellStyle) {
        Row row = sheet.createRow(rowIndex);
        setText(row, 0, rowData.getSerialNo(), cellStyle);
        setText(row, 1, safeText(data.getProjectName()), cellStyle);
        setText(row, 2, safeText(rowData.getOutputType()), cellStyle);
        setText(row, 3, safeText(rowData.getDesignContent()), leftCellStyle);
        setText(row, 4, textOrBlank(rowData.getProjectManagerQuarterOneAmountWan()), cellStyle);
        setText(row, 5, textOrBlank(rowData.getProjectManagerQuarterTwoAmountWan()), cellStyle);
        setText(row, 6, textOrBlank(rowData.getProjectManagerQuarterThreeAmountWan()), cellStyle);
        setText(row, 7, textOrBlank(rowData.getProjectManagerQuarterFourAmountWan()), cellStyle);
        setText(row, 8, textOrBlank(rowData.getProjectManagerYearTotalAmountWan()), cellStyle);
        setText(row, 9, textOrBlank(rowData.getEngineeringPrincipalQuarterOneAmountWan()), cellStyle);
        setText(row, 10, textOrBlank(rowData.getEngineeringPrincipalQuarterTwoAmountWan()), cellStyle);
        setText(row, 11, textOrBlank(rowData.getEngineeringPrincipalQuarterThreeAmountWan()), cellStyle);
        setText(row, 12, textOrBlank(rowData.getEngineeringPrincipalQuarterFourAmountWan()), cellStyle);
        setText(row, 13, textOrBlank(rowData.getEngineeringPrincipalYearTotalAmountWan()), cellStyle);
    }

    private void writeSheet2SubtotalRow(Sheet sheet, int rowIndex, LeadQuarterRow rowData, CellStyle subtotalStyle) {
        Row row = sheet.createRow(rowIndex);
        setText(row, 0, "", subtotalStyle);
        setText(row, 1, "", subtotalStyle);
        setMergedRegionText(sheet, rowIndex, rowIndex, 2, 3, safeText(rowData.getDesignContent()), subtotalStyle);
        setText(row, 4, textOrBlank(rowData.getProjectManagerQuarterOneAmountWan()), subtotalStyle);
        setText(row, 5, textOrBlank(rowData.getProjectManagerQuarterTwoAmountWan()), subtotalStyle);
        setText(row, 6, textOrBlank(rowData.getProjectManagerQuarterThreeAmountWan()), subtotalStyle);
        setText(row, 7, textOrBlank(rowData.getProjectManagerQuarterFourAmountWan()), subtotalStyle);
        setText(row, 8, textOrBlank(rowData.getProjectManagerYearTotalAmountWan()), subtotalStyle);
        setText(row, 9, textOrBlank(rowData.getEngineeringPrincipalQuarterOneAmountWan()), subtotalStyle);
        setText(row, 10, textOrBlank(rowData.getEngineeringPrincipalQuarterTwoAmountWan()), subtotalStyle);
        setText(row, 11, textOrBlank(rowData.getEngineeringPrincipalQuarterThreeAmountWan()), subtotalStyle);
        setText(row, 12, textOrBlank(rowData.getEngineeringPrincipalQuarterFourAmountWan()), subtotalStyle);
        setText(row, 13, textOrBlank(rowData.getEngineeringPrincipalYearTotalAmountWan()), subtotalStyle);
    }

    private void writeSheet2SignatureRow(Sheet sheet, int rowIndex, ExportData data, CellStyle signatureStyle) {
        sheet.createRow(rowIndex);
        setMergedRegionText(sheet, rowIndex, rowIndex, 0, 6,
                defaultLabel(data.getCenterSignerLabel(), DEFAULT_CENTER_SIGNER), signatureStyle);
        setMergedRegionText(sheet, rowIndex, rowIndex, 7, 13,
                defaultLabel(data.getProjectSignerLabel(), DEFAULT_PROJECT_SIGNER), signatureStyle);
    }

    private void mergeProjectNameColumn(Sheet sheet, int startRow, int endRow, ExportData data, CellStyle style) {
        if (startRow < 0 || endRow < startRow) {
            return;
        }
        setMergedRegionText(sheet, startRow, endRow, 1, 1, safeText(data.getProjectName()), style);
    }

    private void mergeOutputTypeColumn(Sheet sheet, int bodyStartRow, List<LeadQuarterRow> rows, CellStyle style) {
        if (rows == null || rows.isEmpty()) {
            return;
        }
        int groupStartIndex = -1;
        String currentOutputType = "";
        for (int i = 0; i < rows.size(); i++) {
            if (Boolean.TRUE.equals(rows.get(i).getSubtotalRow())) {
                if (groupStartIndex >= 0) {
                    setMergedRegionText(sheet, bodyStartRow + groupStartIndex, bodyStartRow + i - 1,
                            2, 2, currentOutputType, style);
                    groupStartIndex = -1;
                    currentOutputType = "";
                }
                continue;
            }
            if (groupStartIndex < 0) {
                groupStartIndex = i;
                currentOutputType = safeText(rows.get(i).getOutputType());
                continue;
            }
            String nextOutputType = safeText(rows.get(i).getOutputType());
            if (!currentOutputType.equals(nextOutputType)) {
                setMergedRegionText(sheet, bodyStartRow + groupStartIndex, bodyStartRow + i - 1,
                        2, 2, currentOutputType, style);
                groupStartIndex = i;
                currentOutputType = nextOutputType;
            }
        }
        if (groupStartIndex >= 0) {
            setMergedRegionText(sheet, bodyStartRow + groupStartIndex, bodyStartRow + rows.size() - 1,
                    2, 2, currentOutputType, style);
        }
    }

    private List<LeadQuarterRow> resolveDetailRows(ExportData data) {
        if (data == null || data.getRows() == null || data.getRows().isEmpty()) {
            return new ArrayList<>();
        }
        List<LeadQuarterRow> rows = new ArrayList<>(data.getRows());
        rows.sort(Comparator
                .comparingInt((LeadQuarterRow row) -> outputTypeOrder(row.getOutputType()))
                .thenComparing(LeadQuarterRow::getSerialNo, Comparator.nullsLast(Integer::compareTo)));
        return rows;
    }

    private List<LeadQuarterRow> resolveSheet2Rows(ExportData data) {
        List<LeadQuarterRow> detailRows = resolveDetailRows(data);
        if (detailRows.isEmpty()) {
            return detailRows;
        }
        List<LeadQuarterRow> rows = new ArrayList<>(detailRows);
        rows.add(buildSheet2SubtotalRow(detailRows));
        return rows;
    }

    private LeadQuarterRow buildSheet2SubtotalRow(List<LeadQuarterRow> groupRows) {
        LeadQuarterRow row = new LeadQuarterRow();
        row.setOutputType("");
        row.setDesignContent("总计");
        row.setSubtotalRow(Boolean.TRUE);
        for (LeadQuarterRow detailRow : groupRows) {
            row.setProjectManagerQuarterOneAmountWan(addAmount(row.getProjectManagerQuarterOneAmountWan(),
                    detailRow.getProjectManagerQuarterOneAmountWan()));
            row.setProjectManagerQuarterTwoAmountWan(addAmount(row.getProjectManagerQuarterTwoAmountWan(),
                    detailRow.getProjectManagerQuarterTwoAmountWan()));
            row.setProjectManagerQuarterThreeAmountWan(addAmount(row.getProjectManagerQuarterThreeAmountWan(),
                    detailRow.getProjectManagerQuarterThreeAmountWan()));
            row.setProjectManagerQuarterFourAmountWan(addAmount(row.getProjectManagerQuarterFourAmountWan(),
                    detailRow.getProjectManagerQuarterFourAmountWan()));
            row.setProjectManagerYearTotalAmountWan(addAmount(row.getProjectManagerYearTotalAmountWan(),
                    detailRow.getProjectManagerYearTotalAmountWan()));
            row.setEngineeringPrincipalQuarterOneAmountWan(addAmount(row.getEngineeringPrincipalQuarterOneAmountWan(),
                    detailRow.getEngineeringPrincipalQuarterOneAmountWan()));
            row.setEngineeringPrincipalQuarterTwoAmountWan(addAmount(row.getEngineeringPrincipalQuarterTwoAmountWan(),
                    detailRow.getEngineeringPrincipalQuarterTwoAmountWan()));
            row.setEngineeringPrincipalQuarterThreeAmountWan(addAmount(row.getEngineeringPrincipalQuarterThreeAmountWan(),
                    detailRow.getEngineeringPrincipalQuarterThreeAmountWan()));
            row.setEngineeringPrincipalQuarterFourAmountWan(addAmount(row.getEngineeringPrincipalQuarterFourAmountWan(),
                    detailRow.getEngineeringPrincipalQuarterFourAmountWan()));
            row.setEngineeringPrincipalYearTotalAmountWan(addAmount(row.getEngineeringPrincipalYearTotalAmountWan(),
                    detailRow.getEngineeringPrincipalYearTotalAmountWan()));
        }
        return row;
    }

    private BigDecimal addAmount(BigDecimal left, BigDecimal right) {
        return amount(left).add(amount(right));
    }

    private int outputTypeOrder(String outputType) {
        int index = OUTPUT_TYPE_ORDER.indexOf(safeText(outputType));
        return index >= 0 ? index : OUTPUT_TYPE_ORDER.size();
    }

    private String resolveProjectManagerNames(ExportData data) {
        if (data == null) {
            return "";
        }
        String displayName = safeText(data.getProjectManagerNames());
        if (!displayName.isEmpty()) {
            return displayName;
        }
        return resolveFallbackNames(data.getRows(), true);
    }

    private String resolveEngineeringPrincipalNames(ExportData data) {
        if (data == null) {
            return "";
        }
        String displayName = safeText(data.getEngineeringPrincipalNames());
        if (!displayName.isEmpty()) {
            return displayName;
        }
        return resolveFallbackNames(data.getRows(), false);
    }

    private String resolveFallbackNames(List<LeadQuarterRow> rows, boolean projectManager) {
        if (rows == null || rows.isEmpty()) {
            return "";
        }
        for (LeadQuarterRow row : rows) {
            if (row == null) {
                continue;
            }
            String current = projectManager ? row.getProjectManagerNames() : row.getEngineeringPrincipalNames();
            if (!safeText(current).isEmpty()) {
                return safeText(current);
            }
        }
        return "";
    }

    private String defaultLabel(String value, String fallback) {
        String text = safeText(value);
        return text.isEmpty() ? fallback : text;
    }

    private String percentTextOrBlank(BigDecimal value) {
        return value == null ? "" : percentText(value);
    }

    private String textOrBlank(BigDecimal value) {
        return value == null ? "" : text(value);
    }

    @Data
    public static class ExportData {
        private String projectName;
        private Integer year;
        private String projectManagerNames;
        private String engineeringPrincipalNames;
        private String centerSignerLabel;
        private String projectSignerLabel;
        private List<LeadQuarterRow> rows;
    }

    @Data
    public static class LeadQuarterRow {
        private Integer serialNo;
        private String outputType;
        private String designContent;
        private Boolean subtotalRow;
        private String projectManagerNames;
        private BigDecimal projectManagerRatio;
        private String engineeringPrincipalNames;
        private BigDecimal engineeringPrincipalRatio;
        private BigDecimal projectManagerQuarterOneAmountWan;
        private BigDecimal projectManagerQuarterTwoAmountWan;
        private BigDecimal projectManagerQuarterThreeAmountWan;
        private BigDecimal projectManagerQuarterFourAmountWan;
        private BigDecimal projectManagerYearTotalAmountWan;
        private BigDecimal engineeringPrincipalQuarterOneAmountWan;
        private BigDecimal engineeringPrincipalQuarterTwoAmountWan;
        private BigDecimal engineeringPrincipalQuarterThreeAmountWan;
        private BigDecimal engineeringPrincipalQuarterFourAmountWan;
        private BigDecimal engineeringPrincipalYearTotalAmountWan;
    }

}
