package net.northking.cctp.dataPool.utils;

import net.northking.cctp.dataPool.dto.dataSets.DataContentDto;
import net.northking.cctp.dataPool.dto.dataSets.DataHeaderDto;
import net.northking.cctp.dataPool.dto.dataSets.DataSetsSaveDto;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class ExcelUtils {
    /**
     * 日志
     */
    private final static Logger logger = LoggerFactory.getLogger(ExcelUtils.class);

    public static Workbook exportToExcel(DataSetsSaveDto saveDto, String sheetName, Boolean isXssf){
        Workbook workbook = null;
        if (isXssf) {
            workbook = new XSSFWorkbook();
        } else {
            workbook = new HSSFWorkbook();
        }
        //工作表
        Sheet sheet = workbook.createSheet(sheetName);
        if (null == saveDto) {
            return workbook;
        }
        List<DataHeaderDto> headers = saveDto.getTableHeader();
        Map<String, List<DataContentDto>> data = saveDto.getTableContent();
        //无表头则直接返回空表
        if (CollectionUtils.isEmpty(headers)) {
            return workbook;
        }
        //表头
        Row headerRow = sheet.createRow(0);
        Map<Integer, Integer> columnWidth = new HashMap<>();
        //设置表头样式
        CellStyle headerStyle = getHeaderStyle(workbook);
        for (int i = 0; i < headers.size(); i++) {
            DataHeaderDto headerDto = headers.get(i);
            if (null == headerDto) continue;
            Cell cell = getHeaderCell(headerDto,headerRow,i,sheet);
            String name = headerDto.getName();
            int width = name.getBytes().length * 256 + 512;
            if (width > 15000) {
                width = 15000;
            }
            columnWidth.put(i, width);
            cell.setCellValue(name);
            cell.setCellStyle(headerStyle);
        }
        //数据样式
        if (!CollectionUtils.isEmpty(data)) {
            CellStyle bodyStyle = getBodyStyle(workbook);
            List<Map<String, Object>> rowMapList = getRowMapList(saveDto);
            for (int rowNum = 0; rowNum < rowMapList.size(); rowNum++) {
                Map<String, Object> rowMap = rowMapList.get(rowNum);
                Row row = sheet.createRow(rowNum + 1);
                for (int colNum = 0; colNum < headers.size(); colNum++) {
                    DataHeaderDto header = headers.get(colNum);
                    Cell cell = getBodyCell(header, rowMap,row,rowNum,colNum,columnWidth);
                    if (null == cell) break;
                    cell.setCellStyle(bodyStyle);
                }
            }
        }
        //设置列宽
        for (int i = 0; i < headers.size(); i++) {
            sheet.setColumnWidth(i,columnWidth.get(i));
        }
        return workbook;
    }

    /**
     * 获取行结构数据
     * @param dto
     * @return
     */
    private static List<Map<String,Object>> getRowMapList(DataSetsSaveDto dto) {
        List<Map<String,Object>> res = new ArrayList<>();
        List<DataHeaderDto> tableHeader = dto.getTableHeader();
        Map<String, List<DataContentDto>> tableContent = dto.getTableContent();
        if (CollectionUtils.isEmpty(tableHeader) || CollectionUtils.isEmpty(tableContent)) {
            return res;
        }
        List<String> nameList = new ArrayList<>();
        int rowNum = 0;
        //统计各列数据最大行数
        for (int i = 0; i < tableHeader.size(); i++) {
            DataHeaderDto headerDto = tableHeader.get(i);
            if (null == headerDto) continue;
            nameList.add(headerDto.getName());
            List<DataContentDto> contentDtos = tableContent.get(headerDto.getName());
            //最大行数与当前列数据量比较
            rowNum = (contentDtos.size() > rowNum) ? contentDtos.size() : rowNum;
        }
        //整理每行数据
        for(int i = 0; i < rowNum; i++) {
            Map<String,Object> row = new HashMap<>();
            for(int j = 0; j < nameList.size(); j++) {
                String name = nameList.get(j);
                List<DataContentDto> columnData = tableContent.get(name);
                //如果该格无数据则存空串
                if (CollectionUtils.isEmpty(columnData) || columnData.size() <= i) {
                    row.put(name,"");
                } else {
                    row.put(name, columnData.get(i).getValue());
                }
            }
            res.add(row);
        }
        return res;
    }

    private static Cell getBodyCell(DataHeaderDto header, Map<String, Object> rowMap, Row row, int rowNum, int columnNum, Map<Integer, Integer> columnWidth) {
        Cell cell = null;
        String type = header.getType();
        String name = header.getName();
        if (null != rowMap.get(name)) {
            Object o = rowMap.get(name);
            if ("boolean".equals(type)) {
                cell = row.createCell(columnNum, CellType.BOOLEAN);
                cell.setCellValue(Boolean.parseBoolean(o.toString()));
            } else {
                cell = row.createCell(columnNum, CellType.STRING);
                String value = o.toString();
                Integer width = columnWidth.get(columnNum);
                int newWidth = value.getBytes().length * 256 + 200;
                if (newWidth > width && newWidth <= 15000) {
                    columnWidth.put(columnNum, newWidth);
                } else if (newWidth > 15000) {
                    columnWidth.put(columnNum, 15000);
                }
                cell.setCellValue(value);
            }
        }else {
            //未传值则存空字符串
            cell = row.createCell(columnNum, CellType.STRING);
            Integer width = columnWidth.get(columnNum);
            columnWidth.put(columnNum, width>200 ? width : 200);
            cell.setCellValue("");
        }
        return cell;
    }

    private static Cell getHeaderCell(DataHeaderDto dataMap, Row row, int index,Sheet sheet) {
        Cell cell = null;
        String type = dataMap.getType();
        if ("date".equals(type)) {
            cell = row.createCell(index, CellType.NUMERIC);
        } else if ("int".equals(type)) {
            cell = row.createCell(index, CellType.NUMERIC);
        } else if ("boolean".equals(type)) {
            cell = row.createCell(index, CellType.BOOLEAN);
        } else {
            cell = row.createCell(index, CellType.STRING);
        }
        return cell;
    }

    private static CellStyle getHeaderStyle(Workbook workbook) {
        CellStyle headerStyle = workbook.createCellStyle();
        headerStyle.setAlignment(HorizontalAlignment.CENTER);  //水平居中
        headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中
        headerStyle.setWrapText(true);   //自动换行
        headerStyle.setBorderTop(BorderStyle.THIN);   //边框
        headerStyle.setBorderBottom(BorderStyle.THIN);
        headerStyle.setBorderLeft(BorderStyle.THIN);
        headerStyle.setBorderRight(BorderStyle.THIN);
        //字体
        Font headerFont = workbook.createFont();
        headerFont.setFontName("黑体");
        headerFont.setFontHeightInPoints((short) 14);
        headerStyle.setFont(headerFont);
        //背景
        headerStyle.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());
        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return headerStyle;
    }

    private static CellStyle getBodyStyle(Workbook workbook) {
        CellStyle headerStyle = workbook.createCellStyle();
        headerStyle.setAlignment(HorizontalAlignment.CENTER);  //水平居中
        headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中
        headerStyle.setWrapText(true);   //自动换行
        headerStyle.setBorderTop(BorderStyle.THIN);   //边框
        headerStyle.setBorderBottom(BorderStyle.THIN);
        headerStyle.setBorderLeft(BorderStyle.THIN);
        headerStyle.setBorderRight(BorderStyle.THIN);
        //字体
        Font headerFont = workbook.createFont();
        headerFont.setFontName("宋体");
        headerFont.setFontHeightInPoints((short) 12);
        headerStyle.setFont(headerFont);
        return headerStyle;
    }
}
