package com.bonus.material.utils;

import com.bonus.common.core.annotation.Excel;
import com.bonus.common.core.utils.poi.ExcelUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;

/**
 * 自定义的 ExcelUtil，全表所有单元格都水平居中
 * 通过后处理方式，在生成Excel后修改所有单元格样式
 */
public class CenterExcelUtil<T> extends ExcelUtil<T> {

    public CenterExcelUtil(Class<T> clazz) {
        super(clazz);
    }

    /**
     * 重写导入模板导出方法 - 主要方法
     */
    @Override
    public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) {
        try {
            // 1. 将Excel写入到字节数组（而不是直接写入响应）
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            HttpServletResponse tempResponse = createTempResponse(response, baos);

            // 2. 调用父类方法生成模板
            super.importTemplateExcel(tempResponse, sheetName, title);

            // 3. 获取生成的Excel字节数组
            byte[] excelBytes = baos.toByteArray();

            // 4. 应用居中样式
            byte[] centeredExcelBytes = applyCenterStyle(excelBytes);

            // 5. 设置响应头并写入处理后的Excel
            setupResponseHeaders(response, sheetName);
            response.getOutputStream().write(centeredExcelBytes);
            response.getOutputStream().flush();

        } catch (Exception e) {
            throw new RuntimeException("导出Excel模板失败", e);
        }
    }

    /**
     * 创建临时响应对象，用于捕获Excel字节数据
     */
    private HttpServletResponse createTempResponse(HttpServletResponse originalResponse, ByteArrayOutputStream baos) throws IOException {
        return new HttpServletResponseWrapper(originalResponse) {
            @Override
            public javax.servlet.ServletOutputStream getOutputStream() {
                return new javax.servlet.ServletOutputStream() {
                    @Override
                    public void write(int b) {
                        baos.write(b);
                    }

                    @Override
                    public boolean isReady() {
                        return true;
                    }

                    @Override
                    public void setWriteListener(javax.servlet.WriteListener writeListener) {
                        // 空实现
                    }
                };
            }
        };
    }

    /**
     * 应用居中样式到所有单元格
     */
    private byte[] applyCenterStyle(byte[] excelBytes) throws IOException {
        try (ByteArrayInputStream bais = new ByteArrayInputStream(excelBytes);
             Workbook workbook = WorkbookFactory.create(bais);
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

            // 创建居中样式（用于空白单元格）
            CellStyle centerStyle = workbook.createCellStyle();
            centerStyle.setAlignment(HorizontalAlignment.CENTER);
            centerStyle.setVerticalAlignment(VerticalAlignment.CENTER);

            // 使用Map缓存已处理的样式，避免创建过多样式对象（POI有64000个样式的限制）
            java.util.Map<Short, CellStyle> styleCache = new java.util.HashMap<>();

            // 遍历所有工作表
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                Sheet sheet = workbook.getSheetAt(i);
                if (sheet == null) continue;

                // 获取表头行以确定列数
                Row headerRow = sheet.getRow(sheet.getFirstRowNum());
                if (headerRow == null) continue;

                // 获取实际的列数，取表头列数和11（A-K列）的最大值
                int headerColNum = headerRow.getLastCellNum();
                int maxColNum = Math.max(headerColNum, 11); // 确保至少包含A-K列（0-10）

                // 预创建足够多的行（例如1000行），并为所有单元格设置居中样式
                // 这样用户在任何位置输入内容时都会自动居中
                int maxRows = 1000; // 可以根据需要调整行数
                for (int rowIndex = 0; rowIndex < maxRows; rowIndex++) {
                    Row row = sheet.getRow(rowIndex);
                    if (row == null) {
                        row = sheet.createRow(rowIndex);
                    }

                    // 为该行的所有列创建单元格并设置居中样式（A-K列，即0-10）
                    for (int colIndex = 0; colIndex < maxColNum; colIndex++) {
                        Cell cell = row.getCell(colIndex);
                        if (cell == null) {
                            cell = row.createCell(colIndex);
                        }

                        // 获取或创建居中样式
                        CellStyle existingStyle = cell.getCellStyle();
                        short styleIndex = existingStyle.getIndex();

                        // 检查缓存中是否已有该样式的居中版本
                        CellStyle centeredStyle = styleCache.get(styleIndex);
                        if (centeredStyle == null) {
                            // 创建新的居中样式
                            if (styleIndex == 0) {
                                // 默认样式，使用预创建的居中样式
                                centeredStyle = centerStyle;
                            } else {
                                // 自定义样式，复制并添加居中
                                centeredStyle = workbook.createCellStyle();
                                centeredStyle.cloneStyleFrom(existingStyle);
                                centeredStyle.setAlignment(HorizontalAlignment.CENTER);
                                centeredStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                            }
                            // 缓存样式
                            styleCache.put(styleIndex, centeredStyle);
                        }

                        // 应用居中样式
                        cell.setCellStyle(centeredStyle);
                    }
                }
            }

            workbook.write(baos);
            return baos.toByteArray();
        }
    }

    /**
     * 设置响应头
     */
    private void setupResponseHeaders(HttpServletResponse response, String fileName) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String encodedFileName = java.net.URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodedFileName + ".xlsx");
    }
}