package cn.pluss.platform.util.excel;

import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.util.ExcelUtil;
import cn.pluss.platform.util.excel.model.Cell;
import cn.pluss.platform.util.excel.model.Row;
import cn.pluss.platform.util.excel.model.Sheet;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.http.MediaType;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;

/**
 * 复杂的excel导出工具
 * @author Djh
 */
public class ComplexExcelUtil {

    /**
     * 标题的样式
     */
    public static XSSFCellStyle getHeaderStyle(XSSFWorkbook workbook) {
        DefaultIndexedColorMap colorMap = new DefaultIndexedColorMap();
        XSSFColor titleBgColor = new XSSFColor(new Color(0xDD, 0xEB, 0xF7), colorMap);

        XSSFCellStyle cellStyle = workbook.createCellStyle();
        ExcelUtil.setCellStyle(cellStyle);
        cellStyle.setFillForegroundColor(titleBgColor);
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        XSSFFont font = workbook.createFont();
        font.setFontHeight(12);
        font.setFontName("宋体");
        font.setBold(true);
        cellStyle.setFont(font);

        return cellStyle;
    }

    public static void setResponseHeader(HttpServletResponse response, String fileName) {
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        String headerValue = "attachment;";
        headerValue += " filename=\"" + ExcelUtil.encodeURIComponent(fileName + ".xlsx") +"\";";
        headerValue += " filename*=utf-8''" + ExcelUtil.encodeURIComponent(fileName + ".xlsx");
        response.setHeader("Content-Disposition", headerValue);
    }

    public interface Transformer<T> {
        /**
         * 获取标题Row
         * @param workbook  workbook
         * @param dataList  数据
         * @return title的row
         */
        Row getHeader(XSSFWorkbook workbook, List<T> dataList);

        /**
         * 将实体类数据转化为Row
         * @param workbook workbook
         * @param t 实体类数据
         * @param scaleCol 列偏移量
         * @param scaleRow 行偏移量
         * @param position 序号
         * @return 单条数据的row
         */
        Row getRow(XSSFWorkbook workbook, T t, int scaleCol, int scaleRow, int position);
    }

    public static <T> void export(String fileName, String sheetName, List<T> dataList, Transformer<T> transformer, HttpServletResponse response) throws IOException {
        // 声明一个工作薄
        XSSFWorkbook workbook = setData(sheetName, dataList, transformer);

        setResponseHeader(response, fileName);
        ServletOutputStream out = response.getOutputStream();
        workbook.write(out);
    }

    public static <T> XSSFWorkbook setData(String sheetName, List<T> dataList, Transformer<T> transformer) {
        XSSFWorkbook workbook = new XSSFWorkbook();
        // 生成一个表格
        XSSFSheet xssfSheet = workbook.createSheet(sheetName);
        // 设置表格默认列宽度为15个字节
        xssfSheet.setDefaultColumnWidth(15);

        XSSFCellStyle cellStyle = workbook.createCellStyle();
        ExcelUtil.setCellStyle(cellStyle);
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        XSSFFont font = workbook.createFont();
        font.setFontHeight(12);
        font.setFontName("宋体");
        cellStyle.setFont(font);

        Sheet sheet = new Sheet(xssfSheet);
        sheet.setCellStyle(cellStyle);
        Row header = transformer.getHeader(workbook, dataList);
        header.setCellStyle(getHeaderStyle(workbook));
        header.add2Sheet(sheet);

        int scaleRow = header.getSpanRow();

        for (int i=0; i<dataList.size(); i++) {
            T item = dataList.get(i);
            Row row = transformer.getRow(workbook, item, 0, scaleRow, i);
            row.setCellStyle(cellStyle);
            sheet.addRow(row);
            scaleRow += row.getSpanRow();
        }

        return workbook;
    }

    public static <T> XSSFWorkbook addData(XSSFWorkbook workbook, String sheetName, List<T> dataList, Transformer<T> transformer) {
        if (workbook == null) {
            throw new MsgException("workBook can't be null");
        }

        // 生成一个表格
        XSSFSheet xssfSheet = workbook.createSheet(sheetName);
        // 设置表格默认列宽度为15个字节
        xssfSheet.setDefaultColumnWidth(15);

        XSSFCellStyle cellStyle = workbook.createCellStyle();
        ExcelUtil.setCellStyle(cellStyle);
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        XSSFFont font = workbook.createFont();
        font.setFontHeight(11);
        font.setFontName("宋体");
        cellStyle.setFont(font);

        Sheet sheet = new Sheet(xssfSheet);
        sheet.setCellStyle(cellStyle);
        sheet.setDateTimeFormatter(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.CHINA));
        Row header = transformer.getHeader(workbook, dataList);
        XSSFCellStyle headerStyle = getHeaderStyle(workbook);
        header.setCellStyle(headerStyle);
        header.add2Sheet(sheet);

        int scaleRow = header.getSpanRow();

        for (int i=0; i<dataList.size(); i++) {
            T item = dataList.get(i);
            Row row = transformer.getRow(workbook, item, 0, scaleRow, i);
            row.setCellStyle(cellStyle);
            sheet.addRow(row);
            scaleRow += row.getSpanRow();
        }

        return workbook;
    }

    /**
     * 同一行添加空的单元格
     * @param cellList  列表
     * @param startCol  开始列
     * @param startRow  开始行
     * @param lengthCol 列宽
     * @param lengthRow 行高
     * @param count     添加单元格个数
     */
    public static void insertEmptyCell(List<Cell> cellList, int startCol, int startRow, int lengthCol, int lengthRow, int count) {
        for (int i=0; i<count; i++) {
            cellList.add(new Cell("", startCol + i, startRow, lengthCol, lengthRow));
        }
    }

    public static void insertEmptyCell(List<Cell> cellList, int startCol, int startRow, int count) {
        insertEmptyCell(cellList, startCol, startRow, 1, 1, count);
    }
}
