package com.openhis.web.reportmanage.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;

/**
 * excel报表做成
 *
 * @author yuxj
 * @date 2025-08-25
 */
public final class ExcelFillerUtil {

    // 时间戳格式：年月日时分秒（确保文件名唯一）
    private static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("yyyyMMddHHmmss");
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * excel报表做成
     *
     * @param dataList DTO对象列表
     * @param headers 表头信息，key为DTO字段名，value为列标题
     * @param fileName 导出的文件名称
     * @param totalValues 表头上的数据，key为DTO字段名，value为值
     * @throws IOException IO异常
     * @throws IllegalAccessException 反射访问异常
     */
    public static void makeExcelFile(HttpServletResponse response, List<?> dataList, Map<String, String> headers,
        String fileName, Map<String, Object> totalValues) throws IOException, IllegalAccessException {

        fileName = fileName + "_" + TIME_FORMATTER.format(new Date()) + ".xlsx";
        // 创建工作簿
        try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            // 转换为泛型列表
            List<Object> genericList = new ArrayList<>(dataList);

            Sheet sheet = workbook.createSheet("数据");

            // 创建行（第0行，Excel行索引从0开始）
            int index = 0;
            int columnIndex;
            if (totalValues != null) {
                // 设置表头上的样式
                CellStyle headerUpStyle = setCellStyle(workbook, BorderStyle.MEDIUM, true);
                headerUpStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 1. 启用实心填充模式（否则背景色不显示）
                headerUpStyle.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
                // 设置表头上的样式
                CellStyle headerUpDateStyle = setCellStyle(workbook, BorderStyle.MEDIUM, true);

                // 填充表头上的数据
                for (Map.Entry<String, Object> entry : totalValues.entrySet()) {
                    Row totalRow = sheet.createRow(index);
                    columnIndex = 0;
                    index++;

                    Cell cell = totalRow.createCell(columnIndex);
                    // 项目名
                    cell.setCellValue(entry.getKey());
                    cell.setCellStyle(headerUpStyle);
                    columnIndex++;
                    // 项目值
                    cell = setDate(totalRow.createCell(columnIndex), entry.getValue(), sheet, columnIndex);
                    cell.setCellStyle(headerUpDateStyle);
                }

                // 加一个空白行
                index++;
            }

            // 创建表头样式
            CellStyle headerStyle = setCellStyle(workbook, BorderStyle.THIN, true);
            headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 1. 启用实心填充模式（否则背景色不显示）
            headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
            // 创建数据单元格样式
            CellStyle dataStyle = setCellStyle(workbook, BorderStyle.THIN, false);

            // 创建表头行
            Row headerRow = sheet.createRow(index);
            columnIndex = 0;

            // 填充表头
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                Cell cell = headerRow.createCell(columnIndex);// 创建单元格
                cell.setCellValue(entry.getValue());// 设置列标题
                cell.setCellStyle(headerStyle);// 应用表头样式
                // 调整合计值列宽度
                if (entry.getValue() != null) {
                    int totalWidth = entry.getValue().getBytes().length * 256;
                    if (sheet.getColumnWidth(columnIndex) < totalWidth) {
                        sheet.setColumnWidth(columnIndex, totalWidth);
                    }
                }
                columnIndex++;
            }
            index++;
            // 填充数据（通过反射获取DTO字段值）
            for (int i = 0; i < genericList.size(); i++) {
                Row dataRow = sheet.createRow(i + index);// 数据行
                Object dto = genericList.get(i);// 获取当前DTO对象
                Class<?> dtoClass = dto.getClass();// 获取DTO的类对象
                columnIndex = 0;

                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    String fieldName = entry.getKey();// 获取DTO字段名
                    Object value = null;

                    try {
                        // 通过反射获取字段值
                        Field field = dtoClass.getDeclaredField(fieldName);
                        field.setAccessible(true); // 允许访问私有字段
                        value = field.get(dto); // 获取字段值
                    } catch (NoSuchFieldException e) {
                        // 如果字段不存在，输出警告信息
                        System.err.println("DTO中不存在字段: " + fieldName);
                    }

                    Cell cell = setDate(dataRow.createCell(columnIndex), value, sheet, columnIndex);
                    cell.setCellStyle(dataStyle);// 应用数据样式
                    columnIndex++;
                }
            }

            workbook.write(outputStream);
            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setContentLength(outputStream.size());

            // 处理文件名编码，防止中文乱码
            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName + ".xlsx");

            // 将字节流写入响应
            response.getOutputStream().write(outputStream.toByteArray());
            response.getOutputStream().flush();
            System.out.print("导出Excel完成");
        } catch (IOException e) {
            System.out.printf("导出Excel失败：" + e.getMessage());
        }
    }

    /**
     * 设置单元格样式
     *
     * @param workbook 工作簿
     * @param borderStyle 边框样式
     * @param bold 是否加粗
     */
    public static CellStyle setCellStyle(Workbook workbook, BorderStyle borderStyle, boolean bold) {
        CellStyle style = workbook.createCellStyle();
        Font font = workbook.createFont();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderBottom(borderStyle);
        style.setBorderLeft(borderStyle);
        style.setBorderRight(borderStyle);
        style.setBorderTop(borderStyle);
        if (bold) {
            font.setBold(true);// 加粗
            style.setFont(font);
        }
        return style;
    }

    /**
     * 根据值的类型设置单元格内容
     *
     * @param cell 工作行
     * @param value 项目值
     * @param sheet 工作页
     * @param columnIndex 工作列
     */
    public static Cell setDate(Cell cell, Object value, Sheet sheet, int columnIndex) {
        if (value != null) {
            // 根据值的类型设置单元格内容
            if (value instanceof BigDecimal) {
                // 保留3位小数，使用HALF_UP模式四舍五入
                BigDecimal scaled = ((BigDecimal)value).setScale(6, RoundingMode.HALF_UP);
                String bdStr = scaled.toPlainString();
                cell.setCellValue(bdStr); // 用字符串写入，避免科学计数法
            } else if (value instanceof Number) {
                cell.setCellValue(((Number)value).doubleValue()); // 数字类型
                if (value instanceof Integer) {
                    cell.setCellValue((Integer)value);
                } else if (value instanceof Long) {
                    cell.setCellValue((Long)value);
                } else {
                    cell.setCellValue(((Number)value).doubleValue());
                }
            } else if (value instanceof Boolean) {
                cell.setCellValue((Boolean)value);// 布尔类型
            } else if (value instanceof Date) {
                String dateStr = DATE_FORMAT.format((Date)value);
                cell.setCellValue(dateStr); // 直接写入原生格式字符串
            } else {
                cell.setCellValue(value.toString());// 其他类型转为字符串
            }

            // 计算内容宽度并调整列宽（中文字符需要特殊处理）
            int contentWidth = value.toString().getBytes().length * 256;
            if (sheet.getColumnWidth(columnIndex) < contentWidth) {
                sheet.setColumnWidth(columnIndex, contentWidth);
            }
        } else {
            cell.setCellValue("");
        }
        return cell;
    }
}