package cn.iocoder.yudao.module.bpm.service.financialpayment;

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MergeSameRowCellsHandler extends AbstractMergeStrategy implements SheetWriteHandler {

    // 记录每行需要合并的区域：<行索引, [起始列, 结束列]列表>
    private final Map<Integer, List<int[]>> mergeMap = new HashMap<>();

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
        // 当前单元格坐标
        int rowIdx = cell.getRowIndex();
        int colIdx = cell.getColumnIndex();

        // 获取当前单元格值（按需处理空值）
        Object cellValue = getCellValue(cell);
        // 跳过空值单元格
        if (cellValue == null || "".equals(cellValue)) {
            return;
        }

        // 初始化该行的合并区域记录
        mergeMap.computeIfAbsent(rowIdx, k -> new ArrayList<>());

        List<int[]> ranges = mergeMap.get(rowIdx);
        if (ranges.isEmpty()) {
            // 第一个单元格直接作为合并起点
            ranges.add(new int[]{colIdx, colIdx});
            return;
        }

        // 获取最后一个合并区域
        int[] lastRange = ranges.get(ranges.size() - 1);
        int lastColEnd = lastRange[1];

        // 如果当前单元格与前一列值相同且连续，则扩展合并区域
        if (colIdx == lastColEnd + 1 && isSameValue(cell, sheet, rowIdx, lastColEnd)) {
            lastRange[1] = colIdx; // 扩展区域右边界
        } else {
            // 创建新合并区域
            ranges.add(new int[]{colIdx, colIdx});
        }
    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        // 调用父类的 merge 方法
        this.merge(writeSheetHolder.getSheet(), cell, head, relativeRowIndex);

        Sheet sheet = writeSheetHolder.getSheet();

        // 应用所有合并区域
        for (Map.Entry<Integer, List<int[]>> entry : mergeMap.entrySet()) {
            int rowIdx = entry.getKey();
            for (int[] range : entry.getValue()) {
                if (range[0] < range[1]) { // 需要合并的列数>1

                    CellRangeAddress newRegion = new CellRangeAddress(rowIdx, rowIdx, range[0], range[1]);

                    // 获取当前 sheet 所有已存在的合并区域
                    List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();

                    // 查找所有与新区域重叠的旧区域并记录其索引
                    List<Integer> toRemoveIndices = new ArrayList<>();
                    for (int i = 0; i < mergedRegions.size(); i++) {
                        CellRangeAddress existingRegion = mergedRegions.get(i);
                        if (isOverlapping(existingRegion, newRegion)) {
                            toRemoveIndices.add(i);
                        }
                    }

                    // 先移除冲突的旧合并区域（注意：索引是动态变化的，应倒序删除）
                    for (int i = toRemoveIndices.size() - 1; i >= 0; i--) {
                        int indexToRemove = toRemoveIndices.get(i);
                        sheet.removeMergedRegion(indexToRemove);
                    }

                    // 添加新的合并区域
                    sheet.addMergedRegion(newRegion);
                }
            }
        }
    }

    // 判断两个合并区域是否有重叠
    private boolean isOverlapping(CellRangeAddress region1, CellRangeAddress region2) {
        return region1.getFirstRow() <= region2.getLastRow() &&
                region1.getLastRow() >= region2.getFirstRow() &&
                region1.getFirstColumn() <= region2.getLastColumn() &&
                region1.getLastColumn() >= region2.getFirstColumn();
    }

    // 比较两个单元格的值是否相同（处理空值）
    private boolean isSameValue(Cell currentCell, Sheet sheet, int row, int col) {
        Cell prevCell = sheet.getRow(row).getCell(col);
        Object val1 = getCellValue(currentCell);
        Object val2 = getCellValue(prevCell);

        if (val1 == null) {
            return val2 == null;
        }
        return val1.equals(val2);
    }

    // 安全获取单元格值
    private Object getCellValue(Cell cell) {
        if (cell == null) {
            return null;
        }
        switch (cell.getCellType()) {
            case STRING: return cell.getStringCellValue();
            case NUMERIC: return cell.getNumericCellValue();
            case BOOLEAN: return cell.getBooleanCellValue();
            default: return null;
        }
    }
}
