package jnpf.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.*;

import java.awt.Color;
import java.text.NumberFormat;
import java.util.List;
import java.util.*;

/**
 * 模板模块EXCEL工具类
 *
 * @author yanwenfu
 * @create 2019-12-29
 */
@Slf4j
public class TemplateExcelUtils {

    public static final String SUFFIX = ".xlsx";

    /** 最大单元格宽度 */
    private static final int MAX_COL_WIDTH = 251;

    private static final String NO_DATA = "无数据";
    public static final int MAX_ROW = 500;

    public static String getEmptyStr(String str) {

        return StringUtils.isEmpty(str) ? "/" : str;
    }

    /**
     * 返回完整文件名
     * @param str 文件名
     * @return java.lang.String
     */
    public static String getFileName(String str) {
        return str + DateDetail.getDate2Str(new Date(), DateDetail.DF5) + SUFFIX;
    }

    /**
     * 无数据的excel
     * @return org.apache.poi.ss.usermodel.Workbook
     */
    public static Workbook createNoDateBook() {
        try {
            XSSFWorkbook workbook = new XSSFWorkbook();
            XSSFSheet sheet = workbook.createSheet();
            XSSFRow row = sheet.createRow(0);
            XSSFCell cell = row.createCell(0);
            cell.setCellValue(NO_DATA);
            return workbook;
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 判断文件后缀名是否与suffix一致
     * @param fileName 文件全名称
     * @param suffix 文件后缀名
     * @return boolean
     */
    public static boolean checkFileType(String fileName, String suffix) {

        // 文件名是否为空
        if (StringUtils.isEmpty(fileName)) {
            return false;
        }
        // 文件后缀是否为.xlsx
        return suffix.equals(fileName.substring(fileName.lastIndexOf(ConstantUtil.POINT_SYMBOL)));
    }

    /**
     * 生成工作簿
     * @param sheets 工作表集合
     * @param dealNull 是否处理dataList的null或""数据
     * @return org.apache.poi.ss.usermodel.Workbook
     */
    public static Workbook createWorkBook(List<TemplateWorkSheet> sheets, boolean dealNull) {

        try {
            // 创建工作簿
            XSSFWorkbook workbook = new XSSFWorkbook();
            //获取列头样式对象
            XSSFCellStyle columnTopStyle = getColumnTopStyle(workbook);
            //单元格样式对象
            XSSFCellStyle style = getStyle(workbook);

            for (TemplateWorkSheet workSheet : sheets) {
                // 创建sheet工作表
                XSSFSheet sheet = workbook.createSheet(workSheet.getSheetName());
                sheet.setDefaultColumnWidth(17);

                // 定义所需列数
                int column;
                if (workSheet.getTitleNum() == 1) {
                    // 列名
                    String[] rowNames = workSheet.getRowNames();
                    column = rowNames.length;
                    XSSFRow row = sheet.createRow(0);
                    // 设置高度
                    row.setHeight((short) (25 * 20));
                    // 将列头设置到sheet的单元格中
                    for (int i = 0; i < column; i++) {
                        // 创建列头对应个数的单元格
                        XSSFCell cell = row.createCell(i);
                        // 设置列头单元格的数据类型
                        cell.setCellType(CellType.STRING);
                        XSSFRichTextString text = new XSSFRichTextString(rowNames[i]);
                        // 设置列头单元格的值
                        cell.setCellValue(text);
                        // 设置列头单元格样式
                        cell.setCellStyle(columnTopStyle);
                    }
                } else {
                    String[][] rowNames = workSheet.getComplexRowNames();
                    column = rowNames[0].length;
                    for (int i = 0; i < rowNames.length; i++) {
                        XSSFRow row = sheet.createRow(i);
                        // 设置高度
                        row.setHeight((short) (25 * 20));
                        for (int j = 0; j < rowNames[i].length; j++) {
                            // 创建列头对应个数的单元格
                            XSSFCell cell = row.createCell(j);
                            // 设置列头单元格的数据类型
                            cell.setCellType(CellType.STRING);
                            XSSFRichTextString text = new XSSFRichTextString(rowNames[i][j]);
                            // 设置列头单元格的值
                            cell.setCellValue(text);
                            // 设置列头单元格样式
                            cell.setCellStyle(columnTopStyle);
                        }
                    }
                }
                // 将查询出的数据设置到sheet对应的单元格中
                List<Object[]> dataList = workSheet.getDataList();
                if (null == dataList || dataList.size() == 0) {
                    // 合并单元格
                    mergeCells(workSheet, sheet);
                    if (workSheet.isHasRemark()) {
                        XSSFCellStyle thisCellStyle = getColumnTopStyle(workbook);
                        thisCellStyle.setAlignment(HorizontalAlignment.LEFT);
                        sheet.getRow(0).getCell(0).setCellStyle(thisCellStyle);
                    }
                    // 生成下拉框
                    Map<String[], int[]> map = workSheet.getDropDownListMap();
                    generateDropDownList(sheet, map);
                    continue;
                }
                // 合并单元格
                mergeCells(workSheet, sheet);
                for (int i = 0; i < dataList.size(); i++) {
                    // 遍历每个对象
                    Object[] obj = dataList.get(i);
                    // 创建所需的行数
                    XSSFRow objRow = sheet.createRow(i + workSheet.getTitleNum());
                    // 设置高度
                    objRow.setHeight((short) (25 * 20));
                    for (int j = 0; j < obj.length; j++) {
                        // 设置单元格的数据类型
                        XSSFCell cell = objRow.createCell(j, CellType.STRING);
                        if (null != obj[j] && (!"".equals(obj[j]))) {
                            // 设置单元格的值
                            cell.setCellValue(obj[j].toString());
                        } else {
                            if (dealNull) {
                                cell.setCellValue("/");
                            } else {
                                cell.setCellValue("");
                            }
                        }
                        // 设置单元格样式
                        cell.setCellStyle(style);
                    }
                }
                // 让列宽随着导出的列长自动适应
                for (int colNum = 0; colNum < column; colNum++) {
                    int columnWidth = sheet.getColumnWidth(colNum) / 256;
                    for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {
                        XSSFRow currentRow;
                        // 当前行未被使用过
                        if (sheet.getRow(rowNum) == null) {
                            currentRow = sheet.createRow(rowNum);
                        } else {
                            currentRow = sheet.getRow(rowNum);
                        }
                        if (currentRow.getCell(colNum) != null) {
                            XSSFCell currentCell = currentRow.getCell(colNum);
                            if (currentCell.getCellType() == CellType.STRING) {
                                int length = currentCell.getStringCellValue().getBytes().length;
                                if (columnWidth < length) {
                                    columnWidth = length;
                                }
                            }
                        }
                    }
                    if (columnWidth > MAX_COL_WIDTH) {
                        columnWidth = MAX_COL_WIDTH;
                    }
                    sheet.setColumnWidth(colNum, (columnWidth + 4) * 256);
                }
            }
            return workbook;
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 生成当前下拉框的坐标
     *
     * @param x x坐标
     * @param y y坐标
     * @return int[]
     */
    public static int[] getCoordinate(int x, int y) {
        int[] coordinate = new int[4];
        coordinate[0] = x;
        coordinate[1] = MAX_ROW;
        coordinate[2] = y;
        coordinate[3] = y;
        return coordinate;
    }

    public static void generateDropDownList(XSSFSheet sheet, Map<String[], int[]> map) {

        if (null != map && map.size() > 0) {
            for (String[] key : map.keySet()) {
                if (key.length > 0) {
                    int[] coordinate = map.get(key);
                    DataValidationHelper dvHelper = sheet.getDataValidationHelper();
                    XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint) dvHelper
                            .createExplicitListConstraint(key);
                    // 第一个参数是开始行，第二个是结束行，第三个是开始列，第四个是结束列
                    CellRangeAddressList addressList = new CellRangeAddressList(coordinate[0], coordinate[1], coordinate[2], coordinate[3]);
                    DataValidation validation = dvHelper.createValidation(dvConstraint, addressList);
                    // 设置只能选下拉菜单里的值不能随便输入
                    validation.setSuppressDropDownArrow(true);
                    validation.setShowErrorBox(true);
                    sheet.addValidationData(validation);
                }
            }
        }
    }

    /**
     * 合并单元格
     * @param workSheet 工作表对象
     * @param sheet 工作表
     */
    private static void mergeCells(TemplateWorkSheet workSheet, XSSFSheet sheet) {
        if (workSheet.getTitleNum() > 1) {
            List<int[]> mergeCells = workSheet.getMergeCells();
            for (int[] mergeCell : mergeCells) {
                CellRangeAddress region = new CellRangeAddress(mergeCell[0], mergeCell[1], mergeCell[2], mergeCell[3]);
                sheet.addMergedRegion(region);
            }
        }
    }

    /**
     * 设置列头样式
     * @param workbook 工作簿
     * @return org.apache.poi.xssf.usermodel.XSSFCellStyle
     */
    private static XSSFCellStyle getColumnTopStyle(XSSFWorkbook workbook) {

        // 设置字体
        XSSFFont font = workbook.createFont();
        // 设置字体大小
        font.setFontHeightInPoints((short) 11);
        // 字体加粗
        font.setBold(true);
        // 设置字体名字
        font.setFontName("宋体");
        // 设置样式;
        XSSFCellStyle style = workbook.createCellStyle();
        setCellStyle(font, style);

        // 设置单元格背景颜色
        style.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        return style;
    }

    private static XSSFCellStyle setCellStyle(XSSFFont font, XSSFCellStyle style) {
        // 设置底边框;
        style.setBorderBottom(BorderStyle.THIN);
        // 设置底边框颜色;
        style.setBottomBorderColor(new XSSFColor(Color.black));
        // 设置左边框;
        style.setBorderLeft(BorderStyle.THIN);
        // 设置左边框颜色;
        style.setLeftBorderColor(new XSSFColor(Color.black));
        // 设置右边框;
        style.setBorderRight(BorderStyle.THIN);
        // 设置右边框颜色;
        style.setRightBorderColor(new XSSFColor(Color.black));
        // 设置顶边框;
        style.setBorderTop(BorderStyle.THIN);
        // 设置顶边框颜色;
        style.setTopBorderColor(new XSSFColor(Color.black));
        // 在样式用应用设置的字体;
        style.setFont(font);
        // 设置自动换行;
        style.setWrapText(false);
        // 设置水平对齐的样式为居中对齐;
        style.setAlignment(HorizontalAlignment.CENTER);
        // 设置垂直对齐的样式为居中对齐;
        style.setVerticalAlignment(VerticalAlignment.CENTER);

        return style;
    }

    /**
     * 列数据信息单元格样式
     * @param workbook 工作簿
     * @return org.apache.poi.xssf.usermodel.XSSFCellStyle
     */
    public static XSSFCellStyle getStyle(XSSFWorkbook workbook) {
        // 设置字体
        XSSFFont font = workbook.createFont();
        font.setFontName("宋体");
        //设置样式;
        XSSFCellStyle style = workbook.createCellStyle();
        setCellStyle(font, style);

        return style;
    }

    /**
     * 返回交集的值
     * @param chooseList 多选val
     * @param value excel val
     * @return java.lang.String
     */
    private static String checkMultiSelectValue(String[] chooseList, String value) {
        String str = "";
        if (chooseList.length < 1 || StringUtils.isEmpty(value)) {
            return str;
        }
        String replace = value.replace("，", ",");
        String[] split = replace.split(",");
        str = getMixed(chooseList, split);
        return str;
    }

    /**
     * 求交集
     * @param chooseList 多选val
     * @param split excel val
     * @return java.lang.String
     */
    private static String getMixed(String[] chooseList, String[] split) {
        List<String> list = new ArrayList<>();
        String[] longArray = chooseList.length > split.length ? chooseList : split;
        String[] shortArray = chooseList.length > split.length ? split : chooseList;
        Set<String> set = new HashSet<>(Arrays.asList(longArray));
        for (String str : shortArray) {
            if (set.contains(str)) {
                list.add(str);
            }
        }
        if (list.size() == 0) {
            return "";
        } else {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < list.size(); i++) {
                if (i == list.size() - 1) {
                    sb.append(list.get(i));
                } else {
                    sb.append(list.get(i)).append(",");
                }
            }
            return sb.toString();
        }
    }

    /**
     * 解析工作表
     * @param sheet 工作表
     * @return java.util.List<java.lang.String[]>
     */
    public static List<String[]> getDataFromSheet(XSSFSheet sheet) {
        List<String[]> list = new ArrayList<>();
        int maxCellNum = sheet.getRow(0).getLastCellNum(); // 获取第一行的最大列数

        for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
            XSSFRow row = sheet.getRow(i);
            if (row == null || row.getPhysicalNumberOfCells() == 0) {
                continue;
            }

            String[] cells = new String[maxCellNum]; // 使用最大列数初始化数组
            boolean hasValidData = false; // 标记是否有有效数据
            for (int j = 0; j < maxCellNum; j++) { // 从0开始遍历到最大列数
                XSSFCell cell = row.getCell(j, XSSFRow.MissingCellPolicy.RETURN_BLANK_AS_NULL); // 使用RETURN_BLANK_AS_NULL策略获取单元格
                if (cell == null) {
                    cells[j] = "";
                } else {
                    cells[j] = getCellValue(cell);
                    if (!cells[j].isEmpty()) {
                        hasValidData = true; // 如果单元格不为空，标记有有效数据
                    }
                }
            }

            if (hasValidData) { // 只有当行中有有效数据时才添加到列表中
                list.add(cells);
            }
        }
        return list;
    }

    /**
     * 解析工作表[包含空行]
     * @param sheet 工作表
     * @return java.util.List<java.lang.String[]>
     */
    public static List<String[]> getDataFromSheetWithNullRow(XSSFSheet sheet) {

        List<String[]> list = new ArrayList<>();
        int maxCellNum = sheet.getRow(0).getLastCellNum(); // 获取第一行的最大列数

        for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
            XSSFRow row = sheet.getRow(i);
            String[] cells = new String[maxCellNum]; // 使用最大列数初始化数组
            if (row == null || row.getPhysicalNumberOfCells() == 0) {
                Arrays.fill(cells, "");
                list.add(cells);
            } else {
                boolean hasValidData = false; // 标记是否有有效数据
                for (int j = 0; j < maxCellNum; j++) { // 从0开始遍历到最大列数
                    XSSFCell cell = row.getCell(j, XSSFRow.MissingCellPolicy.RETURN_BLANK_AS_NULL); // 使用RETURN_BLANK_AS_NULL策略获取单元格
                    if (cell == null) {
                        cells[j] = "";
                    } else {
                        cells[j] = getCellValue(cell);
                        if (!cells[j].isEmpty()) {
                            hasValidData = true; // 如果单元格不为空，标记有有效数据
                        }
                    }
                }
                if (hasValidData) { // 只有当行中有有效数据时才添加到列表中
                    list.add(cells);
                }
            }
        }
        return list;
    }

    /**
     * 解析工作表
     * @param sheet 工作表
     * @return java.util.List<java.lang.String[]>
     */
    public static List<String[]> getDataFromSheetByRow(XSSFSheet sheet) {
        List<String[]> list = new ArrayList<>();
        int len = new String[sheet.getRow(0).getLastCellNum()].length;
        for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i ++) {
            XSSFRow row = sheet.getRow(i);
            if (row == null || row.getPhysicalNumberOfCells() == 0) {
                continue;
            }
            int currentLen = sheet.getRow(i).getLastCellNum();
            len = currentLen >= len ? currentLen : len;
            String[] cells = new String[len];
            for (int j = row.getFirstCellNum(); j < len; j++) {
                XSSFCell cell = row.getCell(j);
                if (null == cell) {
                    cells[j] = "";
                } else {
                    cells[j] = getCellValue(cell);
                }
            }
            list.add(cells);
        }
        return list;
    }

    /**
     * 获取单元格的值
     * @param cell 单元格
     * @return java.lang.String
     */
    private static String getCellValue(XSSFCell cell) {
        String str;
        CellType cellType = cell.getCellTypeEnum();
        if (cellType.equals(CellType.NUMERIC)) {
            if (DateUtil.isCellDateFormatted(cell)) {
                str = DateDetail.getDate2Str(cell.getDateCellValue(), DateDetail.DF4);
            } else {
                NumberFormat nf = NumberFormat.getInstance();
                str = nf.format(cell.getNumericCellValue());
                if (str.contains(",")) {
                    str = str.replace(",", "");
                }
            }
        } else {
            str = cell.getStringCellValue();
        }
        return str;
    }

    /**
     * 解析出下拉框的值
     * @param val 组件属性
     * @return java.lang.String[]
     */
    public static String[] getDropDownList(String val) {
        List<String> list = new ArrayList<>();
        if (StringUtils.isNotEmpty(val)) {
            try {
                if (StringUtils.isNotEmpty(val)) {
                    Map jsonMap = JSONObject.parseObject(val, Map.class);
                    if (null != jsonMap) {
                        JSONArray jsonArray = (JSONArray) jsonMap.get("options");
                        if (null != jsonArray) {
                            for (Object obj : jsonArray) {
                                Map m = (Map) obj;
                                Object o = m.get("selectName");
                                String value = null == o ? "" : o.toString();
                                if (StringUtils.isNotEmpty(value)) {
                                    list.add(value);
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.info(e.getMessage());
                list = new ArrayList<>();
            }
        }
        String[] values = new String[list.size()];
        list.toArray(values);
        return values;
    }

    /**
     * 验证值是否在数组中
     * @param values 数组
     * @param value 值
     * @return java.lang.String
     */
    private static String checkValue(String[] values, String value) {
        String str = "";
        if (values.length < 1) {
            return str;
        }
        for (String val : values) {
            if (val.equals(value)) {
                str = value;
                break;
            }
        }
        return str;
    }

    /**
     * 判读是否为空
     * @param obj 对象
     * @return boolean
     */
    public static boolean isEmpty(Object obj) {
        return null == obj || "".equals(obj);
    }
}
