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.math.RoundingMode;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Component
public class ProjectOverviewOutputExcelBuilder extends AbstractProjectOutputExcelBuilder {

    private static final String SHEET_NAME = "项目总览表";
    private static final String SHEET_FALLBACK_NAME = "项目总览表";
    private static final String TITLE = "7.1.5 项目总览表";

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

    private void buildSheet(Workbook workbook, ExportData data) {
        Sheet sheet = createSheet(workbook, SHEET_NAME, SHEET_FALLBACK_NAME);
        List<EmployeeColumn> employeeColumns = data.getEmployeeColumns() == null
                ? Collections.emptyList() : data.getEmployeeColumns();
        int lastCol = 8 + employeeColumns.size() * 5;
        setColumnWidths(sheet, buildColumnWidths(employeeColumns.size()));

        CellStyle subtitleStyle = createDerivedStyle(workbook, createInfoStyle(workbook),
                null, HorizontalAlignment.CENTER, true, (short) 11);
        CellStyle baseHeaderStyle = createHeaderStyle(workbook);
        CellStyle headerStyle = createDerivedStyle(workbook, baseHeaderStyle,
                IndexedColors.LEMON_CHIFFON, HorizontalAlignment.CENTER, true, (short) 10);
        CellStyle bodyCenterStyle = createDerivedStyle(workbook, createCellStyle(workbook),
                null, HorizontalAlignment.CENTER, false, (short) 10);
        CellStyle bodyLeftStyle = createDerivedStyle(workbook, createCellStyle(workbook),
                null, HorizontalAlignment.LEFT, false, (short) 10);
        CellStyle totalStyle = createDerivedStyle(workbook, baseHeaderStyle,
                IndexedColors.GOLD, HorizontalAlignment.CENTER, true, (short) 10);
        CellStyle totalLeftStyle = createDerivedStyle(workbook, totalStyle,
                IndexedColors.GOLD, HorizontalAlignment.LEFT, true, (short) 10);

        int rowIndex = 0;
        rowIndex = writeSubtitleRow(sheet, rowIndex, data, subtitleStyle, lastCol);
        rowIndex = writeHeader(sheet, rowIndex, employeeColumns, headerStyle);

        if (data.getRows() != null) {
            for (ProjectRow rowData : data.getRows()) {
                writeDataRow(sheet, rowIndex++, rowData, employeeColumns, bodyCenterStyle, bodyLeftStyle);
            }
        }
        writeMergedTotalRow(sheet, rowIndex, data.getTotalRow(), employeeColumns, totalStyle, totalLeftStyle);
    }

    private int writeSubtitleRow(Sheet sheet, int rowIndex, ExportData data, CellStyle style, int lastCol) {
        Row row = getOrCreateRow(sheet, rowIndex);
        for (int cellIndex = 0; cellIndex <= lastCol; cellIndex++) {
            setText(row, cellIndex, "", style);
        }
        if (lastCol <= 0) {
            setText(row, 0, buildSubtitle(data), style);
            return rowIndex + 1;
        }
        setMergedRegionText(sheet, rowIndex, rowIndex, 0, lastCol, buildSubtitle(data), style);
        return rowIndex + 1;
    }

    private String buildSubtitle(ExportData data) {
        String yearText = data == null || data.getYear() == null ? "" : String.valueOf(data.getYear());
        return safeText(yearText) + " 年度 "
                + safeText(data.getOfficeName()) + " 产值汇总（单位：万元）";
    }

    private int writeHeader(Sheet sheet, int rowIndex, List<EmployeeColumn> employeeColumns, CellStyle headerStyle) {
        int topRow = rowIndex;
        sheet.createRow(topRow);
        sheet.createRow(topRow + 1);

        setMergedRegionText(sheet, topRow, topRow + 1, 0, 0, "序号", headerStyle);
        setMergedRegionText(sheet, topRow, topRow + 1, 1, 1, "项目名称", headerStyle);
        setMergedRegionText(sheet, topRow, topRow + 1, 2, 2, "工程进度情况及其它说明", headerStyle);
        setMergedRegionText(sheet, topRow, topRow + 1, 3, 3, "工作阶段", headerStyle);
        setMergedRegionText(sheet, topRow, topRow + 1, 4, 4, "本专业+项目总核算总产值（万元）", headerStyle);
        setMergedRegionText(sheet, topRow, topRow + 1, 5, 5, "往期已发放百分比", headerStyle);
        setMergedRegionText(sheet, topRow, topRow, 6, 7, "本期结算", headerStyle);
        setMergedRegionText(sheet, topRow, topRow + 1, 8, 8, "未结算比例", headerStyle);
        setText(getOrCreateRow(sheet, topRow + 1), 6, "占比", headerStyle);
        setText(getOrCreateRow(sheet, topRow + 1), 7, "考核产值（万元）", headerStyle);

        int columnIndex = 9;
        for (EmployeeColumn employeeColumn : employeeColumns) {
            setMergedRegionText(sheet, topRow, topRow, columnIndex, columnIndex + 4,
                    safeText(employeeColumn.getEmployeeName()), headerStyle);
            Row subRow = getOrCreateRow(sheet, topRow + 1);
            setText(subRow, columnIndex, "一季度", headerStyle);
            setText(subRow, columnIndex + 1, "二季度", headerStyle);
            setText(subRow, columnIndex + 2, "三季度", headerStyle);
            setText(subRow, columnIndex + 3, "四季度", headerStyle);
            setText(subRow, columnIndex + 4, "本年度小计", headerStyle);
            columnIndex += 5;
        }
        return rowIndex + 2;
    }

    private void writeDataRow(Sheet sheet, int rowIndex, ProjectRow rowData, List<EmployeeColumn> employeeColumns,
                              CellStyle bodyCenterStyle, CellStyle bodyLeftStyle) {
        Row row = sheet.createRow(rowIndex);
        setText(row, 0, rowData.getSerialNo(), bodyCenterStyle);
        setText(row, 1, safeText(rowData.getProjectName()), bodyLeftStyle);
        setText(row, 2, safeText(rowData.getProgressText()), bodyLeftStyle);
        setText(row, 3, safeText(rowData.getWorkStage()), bodyLeftStyle);
        setText(row, 4, amountTextOrBlank(rowData.getTotalOutputAmount()), bodyCenterStyle);
        setText(row, 5, percentTextOrBlank(rowData.getHistoricalIssuedRatio()), bodyCenterStyle);
        setText(row, 6, percentTextOrBlank(rowData.getCurrentSettlementRatio()), bodyCenterStyle);
        setText(row, 7, amountTextOrBlank(rowData.getCurrentSettlementAmount()), bodyCenterStyle);
        setText(row, 8, percentTextOrBlank(rowData.getPendingRatio()), bodyCenterStyle);

        Map<Long, EmployeeAmountValue> employeeAmountMap = rowData.getEmployeeAmountMap() == null
                ? Collections.emptyMap() : rowData.getEmployeeAmountMap();
        int columnIndex = 9;
        for (EmployeeColumn employeeColumn : employeeColumns) {
            EmployeeAmountValue value = employeeAmountMap.get(employeeColumn.getEmployeeId());
            setText(row, columnIndex, amountTextOrBlank(value == null ? null : value.getQuarterOneAmount()), bodyCenterStyle);
            setText(row, columnIndex + 1, amountTextOrBlank(value == null ? null : value.getQuarterTwoAmount()), bodyCenterStyle);
            setText(row, columnIndex + 2, amountTextOrBlank(value == null ? null : value.getQuarterThreeAmount()), bodyCenterStyle);
            setText(row, columnIndex + 3, amountTextOrBlank(value == null ? null : value.getQuarterFourAmount()), bodyCenterStyle);
            setText(row, columnIndex + 4, amountTextOrBlank(value == null ? null : value.getAnnualTotalAmount()), bodyCenterStyle);
            columnIndex += 5;
        }
    }

    private void writeTotalRow(Sheet sheet, int rowIndex, ProjectRow totalRow, List<EmployeeColumn> employeeColumns,
                               CellStyle totalStyle, CellStyle totalLeftStyle) {
        ProjectRow rowData = totalRow == null ? new ProjectRow() : totalRow;
        Row row = sheet.createRow(rowIndex);
        setText(row, 0, "", totalStyle);
        setText(row, 1, "合计", totalLeftStyle);
        setText(row, 2, "", totalStyle);
        setText(row, 3, "", totalStyle);
        setText(row, 4, amountTextOrBlank(rowData.getTotalOutputAmount()), totalStyle);
        setText(row, 5, percentTextOrBlank(rowData.getHistoricalIssuedRatio()), totalStyle);
        setText(row, 6, percentTextOrBlank(rowData.getCurrentSettlementRatio()), totalStyle);
        setText(row, 7, amountTextOrBlank(rowData.getCurrentSettlementAmount()), totalStyle);
        setText(row, 8, percentTextOrBlank(rowData.getPendingRatio()), totalStyle);

        Map<Long, EmployeeAmountValue> employeeAmountMap = rowData.getEmployeeAmountMap() == null
                ? Collections.emptyMap() : rowData.getEmployeeAmountMap();
        int columnIndex = 9;
        for (EmployeeColumn employeeColumn : employeeColumns) {
            EmployeeAmountValue value = employeeAmountMap.get(employeeColumn.getEmployeeId());
            setText(row, columnIndex, amountTextOrBlank(value == null ? null : value.getQuarterOneAmount()), totalStyle);
            setText(row, columnIndex + 1, amountTextOrBlank(value == null ? null : value.getQuarterTwoAmount()), totalStyle);
            setText(row, columnIndex + 2, amountTextOrBlank(value == null ? null : value.getQuarterThreeAmount()), totalStyle);
            setText(row, columnIndex + 3, amountTextOrBlank(value == null ? null : value.getQuarterFourAmount()), totalStyle);
            setText(row, columnIndex + 4, amountTextOrBlank(value == null ? null : value.getAnnualTotalAmount()), totalStyle);
            columnIndex += 5;
        }
    }

    private void writeMergedTotalRow(Sheet sheet, int rowIndex, ProjectRow totalRow, List<EmployeeColumn> employeeColumns,
                                     CellStyle totalStyle, CellStyle totalLeftStyle) {
        ProjectRow rowData = totalRow == null ? new ProjectRow() : totalRow;
        Row row = sheet.createRow(rowIndex);
        setMergedRegionText(sheet, rowIndex, rowIndex, 0, 3, "\u5408\u8ba1", totalStyle);
        setText(row, 4, amountTextOrBlank(rowData.getTotalOutputAmount()), totalStyle);
        setText(row, 5, "", totalStyle);
        setText(row, 6, "", totalStyle);
        setText(row, 7, amountTextOrBlank(rowData.getCurrentSettlementAmount()), totalStyle);
        setText(row, 8, "", totalStyle);

        Map<Long, EmployeeAmountValue> employeeAmountMap = rowData.getEmployeeAmountMap() == null
                ? Collections.emptyMap() : rowData.getEmployeeAmountMap();
        int columnIndex = 9;
        for (EmployeeColumn employeeColumn : employeeColumns) {
            EmployeeAmountValue value = employeeAmountMap.get(employeeColumn.getEmployeeId());
            setText(row, columnIndex, amountTextOrBlank(value == null ? null : value.getQuarterOneAmount()), totalStyle);
            setText(row, columnIndex + 1, amountTextOrBlank(value == null ? null : value.getQuarterTwoAmount()), totalStyle);
            setText(row, columnIndex + 2, amountTextOrBlank(value == null ? null : value.getQuarterThreeAmount()), totalStyle);
            setText(row, columnIndex + 3, amountTextOrBlank(value == null ? null : value.getQuarterFourAmount()), totalStyle);
            setText(row, columnIndex + 4, amountTextOrBlank(value == null ? null : value.getAnnualTotalAmount()), totalStyle);
            columnIndex += 5;
        }
    }

    private String amountTextOrBlank(BigDecimal value) {
        if (value == null || amount(value).compareTo(BigDecimal.ZERO) == 0) {
            return "";
        }
        return amount(value).divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP).toPlainString();
    }

    private String percentTextOrBlank(BigDecimal value) {
        if (value == null || ratio(value).compareTo(BigDecimal.ZERO) == 0) {
            return "";
        }
        return percentText(value);
    }

    private int[] buildColumnWidths(int employeeCount) {
        int[] widths = new int[9 + employeeCount * 5];
        widths[0] = 8;
        widths[1] = 24;
        widths[2] = 28;
        widths[3] = 20;
        widths[4] = 18;
        widths[5] = 14;
        widths[6] = 12;
        widths[7] = 14;
        widths[8] = 12;
        for (int i = 9; i < widths.length; i += 5) {
            widths[i] = 12;
            widths[i + 1] = 12;
            widths[i + 2] = 12;
            widths[i + 3] = 12;
            widths[i + 4] = 14;
        }
        return widths;
    }

    @Data
    public static class ExportData {
        private Integer year;
        private String officeName;
        private List<EmployeeColumn> employeeColumns = Collections.emptyList();
        private List<ProjectRow> rows = Collections.emptyList();
        private ProjectRow totalRow;
    }

    @Data
    public static class EmployeeColumn {
        private Long employeeId;
        private String employeeName;
    }

    @Data
    public static class ProjectRow {
        private Integer serialNo;
        private String projectName;
        private String progressText;
        private String workStage;
        private BigDecimal totalOutputAmount;
        private BigDecimal historicalIssuedRatio;
        private BigDecimal currentSettlementRatio;
        private BigDecimal currentSettlementAmount;
        private BigDecimal pendingRatio;
        private Map<Long, EmployeeAmountValue> employeeAmountMap = new LinkedHashMap<>();
    }

    @Data
    public static class EmployeeAmountValue {
        private BigDecimal quarterOneAmount;
        private BigDecimal quarterTwoAmount;
        private BigDecimal quarterThreeAmount;
        private BigDecimal quarterFourAmount;
        private BigDecimal annualTotalAmount;
    }

}
