package com.emergency.avenue.common.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * 导出excel 表格 工具类
 * @author lixiang
 * @date 2023/5/26 10:18
 */
public class EasyExcelUtil implements RowWriteHandler {

	private int mergeRowIndex;//从哪一行开始合并
	private int[] mergeColumnIndex;//excel合并的列
	private int[] signNum;//合并的唯一标识
	private int total;//总行数
	private int lastRow;
	private int firstCol;
	private int lastCol;
	private int firstRow;
	private int mergeCount = 1;

	private EasyExcelUtil(){}

	private EasyExcelUtil(int mergeRowIndex, int[] mergeColumnIndex, int[] signNum, int total) {
		this.mergeRowIndex = mergeRowIndex;
		this.mergeColumnIndex = mergeColumnIndex;
		this.signNum = signNum;
		this.total = total;
	}

	/**
	 * 导出excel
	 * @param response
	 * @param fileName 文件名称
	 * @param exportList 导出数据
	 * @param clazz 导出实体bean class对象
	 * @param <T>
	 * @throws IOException
	 */
	public static <T> void createExcel(HttpServletResponse response, String fileName, List<T> exportList,
									   Class<T> clazz)
			throws IOException {
		createExcel(response,fileName,exportList,clazz,null);
	}

	/**
	 * 导出excel
	 * @param response
	 * @param fileName 文件名称
	 * @param exportList 导出数据
	 * @param clazz 导出实体bean class对象
	 * @param cellMerge 单元格合并规则
	 * @param <T>
	 * @throws IOException
	 */
	public static <T> void createExcel(HttpServletResponse response, String fileName, List<T> exportList,
									   Class<T> clazz, CellMerge cellMerge)
			throws IOException {
		// 设置下载信息
		response.setContentType("application/vnd.ms-excel");
		response.setCharacterEncoding("utf-8");
		fileName = URLEncoder.encode(fileName, "UTF-8");
		response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

		//定义ExcelWriterSheetBuilder
		ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcel
				.write(response.getOutputStream(), clazz)
				.sheet(fileName);

		//合并单元格
		if (cellMerge != null) {
			// 从那一行开始合并
			int mergeRowIndex = 1;
			EasyExcelUtil
					excelMergeRowByRowStrategy = new EasyExcelUtil(mergeRowIndex, cellMerge.getMergeColumIndex(),
					cellMerge.getMergeRuleColumIndex(), exportList.size());
			excelWriterSheetBuilder.registerWriteHandler(excelMergeRowByRowStrategy);
		}

		//设置头样式
		WriteCellStyle headWriteCellStyle = new WriteCellStyle();
		//设置内容格式
		WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
		HorizontalCellStyleStrategy horizontalCellStyleStrategy =
				new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
		//设计内容居中
		contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
		contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
		//设置内容自动换行
		contentWriteCellStyle.setWrapped(true);
		excelWriterSheetBuilder.registerWriteHandler(horizontalCellStyleStrategy);

		//调用doWrite方法
		excelWriterSheetBuilder.doWrite(exportList);
	}

	@Override
	public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {

	}

	@Override
	public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {

	}

	@Override
	public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
								Integer relativeRowIndex, Boolean isHead) {
		//当前行
		int curRowIndex = row.getRowNum();
		//每一行的最大列数
		short lastCellNum = row.getLastCellNum();

		if (curRowIndex == 1) {
			//赋初值 第一行
			firstRow = curRowIndex;
		}
		//开始合并位置
		if (curRowIndex > mergeRowIndex && !row.getCell(0).getStringCellValue().equals("")) {
			for (int i = 0; i < lastCellNum; i++) {
				if (i == mergeColumnIndex[i]) {
					//当前行号 当前行对象 合并的标识位
					mergeWithPrevAnyRow(writeSheetHolder.getSheet(), curRowIndex, row, signNum);
					break;//已经进入到合并单元格操作里面了，执行一次就行
				}
			}
		}
	}

	public void mergeWithPrevAnyRow(Sheet sheet, int curRowIndex, Row row, int[] signNum) {
		Row preRow = row.getSheet().getRow(curRowIndex - 1);
		List<String> rowDataList = new ArrayList<>();
		List<String> preDataList = new ArrayList<>();

		for (int i : signNum) {
			Object currentData =
					row.getCell(i).getCellTypeEnum() == CellType.STRING ? row.getCell(i).getStringCellValue() :
							row.getCell(i).getNumericCellValue();
			Object preData =
					preRow.getCell(i).getCellTypeEnum() == CellType.STRING ? preRow.getCell(i).getStringCellValue() :
							preRow.getCell(i).getNumericCellValue();
			rowDataList.add(String.valueOf(currentData));
			preDataList.add(String.valueOf(preData));
		}

		String rowDataStr = String.join(",", rowDataList);
		String preDataStr = String.join(",", preDataList);

		//判断是否合并单元格
		boolean curEqualsPre = rowDataStr.equals(preDataStr);
		//判断前一个和后一个相同 并且 标识位相同
		if (curEqualsPre) {
			lastRow = curRowIndex;
			mergeCount++;
		}
		//excel过程中合并
		if (!curEqualsPre && mergeCount > 1) {
			mergeSheet(firstRow, lastRow, mergeColumnIndex, sheet);
			mergeCount = 1;
		}

		//excel结尾处合并
		if (mergeCount > 1 && total == curRowIndex) {
			mergeSheet(firstRow, lastRow, mergeColumnIndex, sheet);
			mergeCount = 1;
		}

		if (!curEqualsPre) {
			firstRow = curRowIndex;
		}

	}

	private void mergeSheet(int firstRow, int lastRow, int[] mergeColumnIndex, Sheet sheet) {
		for (int colNum : mergeColumnIndex) {
			firstCol = colNum;
			lastCol = colNum;
			CellRangeAddress cellRangeAddress = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
			sheet.addMergedRegion(cellRangeAddress);
		}
	}

	/**
	 * 单元格合并类
	 */
	@Data
	@AllArgsConstructor
	@NoArgsConstructor
	public class CellMerge {
		private int[] mergeColumIndex;
		private int[] mergeRuleColumIndex;
	}

	/**
	 * 设置单元格合并规则
	 * @param mergeColumIndex
	 * @param mergeRuleColumIndex
	 * @return
	 */
	public static CellMerge setCellMerge(int[] mergeColumIndex,int[] mergeRuleColumIndex){
		EasyExcelUtil excelUtil = new EasyExcelUtil();
		CellMerge cellMerge = excelUtil.new CellMerge();
		cellMerge.setMergeColumIndex(mergeColumIndex);
		cellMerge.setMergeRuleColumIndex(mergeRuleColumIndex);
		return cellMerge;
	}
}

