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

import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.EmployeeOutputSummaryExcelRespVO;
import lombok.Data;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
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.math.RoundingMode;
import java.util.Collections;
import java.util.List;

@Component
public class EmployeeOutputSummaryExcelBuilder extends AbstractProjectOutputExcelBuilder {

    private static final String SHEET_NAME = "员工汇总";
    private static final String TITLE_PREFIX = "7.1.6 ";
    private static final String TITLE_SUFFIX = " 年设计中心员工个人考核产值汇总，全公司产值人员汇总表";
    private static final String SUBTITLE_SUFFIX = " 年设计中心员工个人考核产值汇总（单位：万元）";
    private static final int LAST_COL = 12;
    private static final int DETAIL_START_ROW_NUM = 4;

    public Workbook build(ExportData data) {
        Workbook workbook = createWorkbook();
        workbook.setForceFormulaRecalculation(true);
        buildSheet(workbook, data);
        return workbook;
    }

    private void buildSheet(Workbook workbook, ExportData data) {
        Sheet sheet = createSheet(workbook, SHEET_NAME, SHEET_NAME);
        setColumnWidths(sheet, 8, 14, 12, 12, 12, 12, 12, 14, 14, 18, 14, 14, 14);

        CellStyle subtitleStyle = createDerivedStyle(workbook, createInfoStyle(workbook),
                null, HorizontalAlignment.CENTER, true, (short) 11);
        CellStyle headerStyle = createDerivedStyle(workbook, createHeaderStyle(workbook),
                IndexedColors.LEMON_CHIFFON, HorizontalAlignment.CENTER, true, (short) 10);
        CellStyle cellStyle = createDerivedStyle(workbook, createCellStyle(workbook),
                null, HorizontalAlignment.CENTER, false, (short) 10);
        CellStyle leftCellStyle = createDerivedStyle(workbook, createCellStyle(workbook),
                null, HorizontalAlignment.LEFT, false, (short) 10);
        CellStyle amountStyle = createAmountStyle(workbook, false, false);
        CellStyle formulaStyle = createAmountStyle(workbook, false, false);
        CellStyle totalCellStyle = createDerivedStyle(workbook, createHeaderStyle(workbook),
                IndexedColors.GOLD, HorizontalAlignment.CENTER, true, (short) 10);
        CellStyle totalLeftCellStyle = createDerivedStyle(workbook, totalCellStyle,
                IndexedColors.GOLD, HorizontalAlignment.LEFT, true, (short) 10);
        CellStyle totalStyle = createAmountStyle(workbook, true, false);
        CellStyle totalLeftStyle = createDerivedStyle(workbook, totalStyle,
                null, HorizontalAlignment.LEFT, true, (short) 10);

        int rowIndex = 0;
        rowIndex = writeSubtitleRow(sheet, rowIndex, data, subtitleStyle);
        rowIndex = writeHeaderRow(sheet, rowIndex, headerStyle);

        List<EmployeeOutputSummaryExcelRespVO> rows = data == null || data.getRows() == null
                ? Collections.emptyList() : data.getRows();
        for (EmployeeOutputSummaryExcelRespVO rowData : rows) {
            writeDetailRow(sheet, rowIndex++, rowData, data, cellStyle, leftCellStyle, amountStyle, formulaStyle);
        }
        writeTotalRow(sheet, rowIndex, rows, data, totalCellStyle, totalLeftCellStyle, totalStyle, totalLeftStyle);
    }

    private int writeSubtitleRow(Sheet sheet, int rowIndex, ExportData data, CellStyle style) {
        Row row = sheet.createRow(rowIndex);
        for (int cellIndex = 0; cellIndex <= LAST_COL; cellIndex++) {
            setText(row, cellIndex, "", style);
        }
        setMergedRegionText(sheet, rowIndex, rowIndex, 0, LAST_COL,
                safeYear(data) + SUBTITLE_SUFFIX, style);
        return rowIndex + 1;
    }

    private int writeHeaderRow(Sheet sheet, int rowIndex, CellStyle style) {
        writeRow(sheet, rowIndex, style,
                "序号", "姓名", "第一季度", "第二季度", "第三季度", "第四季度", "年度合计",
                "所长 / BIM 考核产值", "年度考核产值合计", "1~12 月份预计发生成本（含预计精神文明奖）",
                "基本考核产值", "剩余产值", "预估年底绩效");
        return rowIndex + 1;
    }

    private void writeDetailRow(Sheet sheet, int rowIndex, EmployeeOutputSummaryExcelRespVO rowData, ExportData data,
                                CellStyle cellStyle, CellStyle leftCellStyle,
                                CellStyle amountStyle, CellStyle formulaStyle) {
        Row row = sheet.createRow(rowIndex);
        int excelRowNum = rowIndex + 1;
        setText(row, 0, rowData == null || rowData.getSerialNo() == null ? "" : rowData.getSerialNo(), cellStyle);
        setText(row, 1, rowData == null ? "" : safeText(rowData.getEmployeeName()), leftCellStyle);
        setNumericCell(row, 2, rowData == null ? null : rowData.getQuarterOneAmount(), amountStyle);
        setNumericCell(row, 3, rowData == null ? null : rowData.getQuarterTwoAmount(), amountStyle);
        setNumericCell(row, 4, rowData == null ? null : rowData.getQuarterThreeAmount(), amountStyle);
        setNumericCell(row, 5, rowData == null ? null : rowData.getQuarterFourAmount(), amountStyle);
        setNumericCell(row, 6, rowData == null ? null : rowData.getAnnualTotalAmount(), amountStyle);
        setNumericCell(row, 7, rowData == null ? null : rowData.getOfficeLeaderOrBimAmount(), amountStyle);
        setNumericCell(row, 8, rowData == null ? null : rowData.getTotalAssessmentOutputAmount(), amountStyle);
        setNumericCell(row, 9, rowData == null ? null : rowData.getExpectedCostAmount(), amountStyle);

        setFormulaCell(row, 10, buildBasicAssessmentFormula(excelRowNum, data), formulaStyle);
        setFormulaCell(row, 11, buildRemainingOutputFormula(excelRowNum), formulaStyle);
        setFormulaCell(row, 12, buildPerformanceFormula(excelRowNum, data), formulaStyle);
    }

    private void writeTotalRow(Sheet sheet, int rowIndex, List<EmployeeOutputSummaryExcelRespVO> rows, ExportData data,
                               CellStyle totalCellStyle, CellStyle totalLeftCellStyle,
                               CellStyle totalStyle, CellStyle totalLeftStyle) {
        Row row = sheet.createRow(rowIndex);
        int totalExcelRowNum = rowIndex + 1;
        int detailEndRowNum = DETAIL_START_ROW_NUM + rows.size() - 1;

        setText(row, 0, "", totalCellStyle);
        setText(row, 1, "合计", totalLeftCellStyle);
        for (int col = 2; col <= LAST_COL; col++) {
            if (rows.isEmpty()) {
                setNumericCell(row, col, BigDecimal.ZERO, totalStyle);
                continue;
            }
            setFormulaCell(row, col, "SUM(" + columnName(col) + DETAIL_START_ROW_NUM + ":"
                    + columnName(col) + detailEndRowNum + ")", totalStyle);
        }
        // Ensure total-row formulas survive even if Excel recalculation is disabled.
        if (!rows.isEmpty()) {
            row.getCell(10).setCellFormula(buildTotalBasicAssessmentFormula(totalExcelRowNum));
            row.getCell(11).setCellFormula(buildTotalRemainingOutputFormula(totalExcelRowNum));
            row.getCell(12).setCellFormula(buildTotalPerformanceFormula(totalExcelRowNum, data));
        }
    }

    private String buildBasicAssessmentFormula(int excelRowNum, ExportData data) {
        BigDecimal kValue = data == null ? BigDecimal.ZERO : ratio(data.getKValue());
        if (kValue.compareTo(BigDecimal.ZERO) <= 0) {
            return "0";
        }
        return "ROUND(J" + excelRowNum + "/" + kValue.stripTrailingZeros().toPlainString() + ",2)";
    }

    private String buildRemainingOutputFormula(int excelRowNum) {
        return "ROUND(I" + excelRowNum + "-K" + excelRowNum + ",2)";
    }

    private String buildPerformanceFormula(int excelRowNum, ExportData data) {
        BigDecimal kValue = data == null ? BigDecimal.ZERO : ratio(data.getKValue());
        if (kValue.compareTo(BigDecimal.ZERO) <= 0) {
            return "0";
        }
        return "ROUND(L" + excelRowNum + "*" + kValue.stripTrailingZeros().toPlainString() + ",2)";
    }

    private String buildTotalBasicAssessmentFormula(int excelRowNum) {
        return "SUM(K" + DETAIL_START_ROW_NUM + ":K" + (excelRowNum - 1) + ")";
    }

    private String buildTotalRemainingOutputFormula(int excelRowNum) {
        return "SUM(L" + DETAIL_START_ROW_NUM + ":L" + (excelRowNum - 1) + ")";
    }

    private String buildTotalPerformanceFormula(int excelRowNum, ExportData data) {
        return "SUM(M" + DETAIL_START_ROW_NUM + ":M" + (excelRowNum - 1) + ")";
    }

    private String safeYear(ExportData data) {
        return data == null || data.getYear() == null ? "" : String.valueOf(data.getYear());
    }

    private CellStyle createAmountStyle(Workbook workbook, boolean bold, boolean leftAlign) {
        CellStyle base = createCellStyle(workbook);
        CellStyle style = createDerivedStyle(workbook, base, null,
                leftAlign ? HorizontalAlignment.LEFT : HorizontalAlignment.CENTER, bold, (short) 10);
        DataFormat dataFormat = workbook.createDataFormat();
        style.setDataFormat(dataFormat.getFormat("0.00"));
        return style;
    }

    private void setNumericCell(Row row, int cellIndex, BigDecimal value, CellStyle style) {
        Cell cell = row.createCell(cellIndex);
        if (value != null) {
            cell.setCellValue(value.setScale(2, RoundingMode.HALF_UP).doubleValue());
        }
        cell.setCellStyle(style);
    }

    private void setFormulaCell(Row row, int cellIndex, String formula, CellStyle style) {
        Cell cell = row.createCell(cellIndex);
        cell.setCellFormula(formula);
        cell.setCellStyle(style);
    }

    private String columnName(int zeroBasedIndex) {
        int index = zeroBasedIndex;
        StringBuilder builder = new StringBuilder();
        while (index >= 0) {
            builder.insert(0, (char) ('A' + index % 26));
            index = index / 26 - 1;
        }
        return builder.toString();
    }

    @Data
    public static class ExportData {
        private Integer year;
        private BigDecimal kValue;
        private List<EmployeeOutputSummaryExcelRespVO> rows = Collections.emptyList();
    }

}
