package jnpf.attendance.excel;

import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;

/**
 * 考勤本导出单元格合并处理器
 * 使用CellWriteHandler在数据写入过程中执行合并，避免与表头合并冲突
 *
 * @author Generated
 * @date 2026-04-29
 */
@Slf4j
public class AttendanceBookMergeHandler implements CellWriteHandler {

    /**
     * 需要合并的单元格范围列表（数据行索引，不包含表头）
     */
    private final List<CellRangeAddress> mergeCells;

    /**
     * 表头行数（用于偏移数据行索引）
     */
    private final int headerRowCount;

    /**
     * 预期数据总行数（用于判断是否是最后一行）
     */
    private final int expectedDataRowCount;

    /**
     * 额外表头行数（标题行+说明行）
     */
    private final int extraHeaderRows;

    /**
     * 总列数（用于合并标题和说明行）
     */
    private final int totalColumns;

    /**
     * 是否已执行合并
     */
    private boolean merged = false;

    public AttendanceBookMergeHandler(List<CellRangeAddress> mergeCells, int headerRowCount, int expectedDataRowCount, int totalColumns) {
        this.mergeCells = mergeCells;
        this.headerRowCount = headerRowCount;
        this.expectedDataRowCount = expectedDataRowCount;
        this.extraHeaderRows = 0;  // 使用3层表头，不需要额外行
        this.totalColumns = totalColumns;
    }

    @Override
    public void afterCellDispose(CellWriteHandlerContext context) {
        // 只在未合并且是数据行（非表头）时才执行合并
        if (!merged && mergeCells != null && !mergeCells.isEmpty()) {
            Integer rowIndex = context.getRowIndex();
            Boolean isHead = context.getHead();
            
            // 跳过表头行
            if (isHead != null && isHead) {
                return;
            }
            
            // 在写入最后一行数据后执行合并
            if (rowIndex != null && rowIndex >= headerRowCount + expectedDataRowCount - 1) {
                Sheet sheet = context.getWriteSheetHolder().getSheet();
                
                try {
                    int mergedCount = 0;
                    
                    // 合并数据区域（使用3层表头，偏移量为headerRowCount）
                    for (CellRangeAddress address : mergeCells) {
                        int offset = headerRowCount;  // 3层表头
                        CellRangeAddress adjustedAddress = new CellRangeAddress(
                            address.getFirstRow() + offset,
                            address.getLastRow() + offset,
                            address.getFirstColumn(),
                            address.getLastColumn()
                        );
                        
                        // 检查是否与现有合并区域冲突
                        if (!hasConflict(sheet, adjustedAddress)) {
                            sheet.addMergedRegion(adjustedAddress);
                            mergedCount++;
                        } else {
                            log.warn("跳过冲突的合并区域: {}", adjustedAddress);
                        }
                    }
                    merged = true;
                    log.info("考勤本导出单元格合并完成，成功合并 {} 个区域，表头行数: {}, 数据行数: {}", 
                             mergedCount, headerRowCount, expectedDataRowCount);
                } catch (Exception e) {
                    log.error("考勤本导出单元格合并失败: {}", e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 检查合并区域是否与现有合并区域冲突
     */
    private boolean hasConflict(Sheet sheet, CellRangeAddress newAddress) {
        int numMergedRegions = sheet.getNumMergedRegions();
        for (int i = 0; i < numMergedRegions; i++) {
            CellRangeAddress existing = sheet.getMergedRegion(i);
            if (isOverlap(newAddress, existing)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查两个合并区域是否重叠
     */
    private boolean isOverlap(CellRangeAddress addr1, CellRangeAddress addr2) {
        return !(addr1.getLastRow() < addr2.getFirstRow() ||
                 addr1.getFirstRow() > addr2.getLastRow() ||
                 addr1.getLastColumn() < addr2.getFirstColumn() ||
                 addr1.getFirstColumn() > addr2.getLastColumn());
    }
}
