package cn.pluss.platform.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.alibaba.fastjson.JSONObject;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author yuchen
 * 
 * @Description 
 */

public class ExcelUtil {
    public static<T> HSSFWorkbook getHSSFWorkbook( String sheetNmae, String[] title, Collection<T> values){
        return null;
    }

    /**
     * 利用正则的预编译功能
     */
    private static Pattern NUMBER_PATTERN = Pattern.compile("^//d+(//.//d+)?$");

    /**
     * 导出Excel工具
     *
     * @param fileName  文件名
     * @param sheetName sheet名称
     * @param headers   第一列内容，表头
     * @param dataSet   内容
     * @param keyList   map键，用于排序
     * @param response  response
     * @param pattern   日期格式化
     * @throws IOException IO异常
     */
    public static void exportExcel(String fileName, String sheetName, String[] headers,
                                   List<Map<String, Object>> dataSet, String[] keyList, HttpServletResponse response, String pattern) throws IOException {
        exportExcel(fileName, sheetName, headers, dataSet, keyList, new ExcelInfo<Map<String, Object>>() {
            @Override
            public Map<String, Object> getRowDataMap(Map<String, Object> rowData) {
                return rowData;
            }
        }, response, pattern);
    }


    private static <T> void exportExcel(String fileName, String sheetName, String[] headers,
                                        List<T> dataSet, String[] keyList, ExcelInfo<T> iExcelInfo, HttpServletResponse response, String pattern) throws IOException {
        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFCellStyle cellStyle = getCellStyle(workbook);

        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet(sheetName);
        // 设置表格默认列宽度为15个字节
        sheet.setDefaultColumnWidth((short) 15);
        setTitle(sheet, headers);

        HSSFFont font3 = workbook.createFont();
        font3.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());

        // 声明一个画图的顶级管理器
        HSSFPatriarch patriarch = sheet.createDrawingPatriarch();

        // 遍历集合数据，产生数据行
        Iterator<T> it = dataSet.iterator();
        int index = 0;
        while (it.hasNext()) {
            index++;
            T next = it.next();
            Map<String, Object> rowDataMap = null;
            List<Object> rowData = null;
            int dataSize;
            if (keyList != null) {
                rowDataMap = iExcelInfo.getRowDataMap(next);
                dataSize = keyList.length;
            } else {
                rowData = iExcelInfo.getRowData(next);
                dataSize = rowData.size();
            }

            HSSFRow row = sheet.createRow(index);
            //根据key的顺序依次从数据中拿到需要的数据，并生成所需要的单元格
            for (int i = 0; i < dataSize; i++) {
                HSSFCell cell = row.createCell(i);
                cell.setCellStyle(cellStyle);
                Object value;
                if (keyList != null) {
                    String key = keyList[i];
                    value = rowDataMap.get(key);
                } else {
                    value = rowData.get(i);
                }


                String textValue;
                if (value instanceof byte[]) {
                    setPic(row, sheet, patriarch, (byte[]) value, i, index);
                } else {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
                    textValue = getTextObject(value, formatter);
                    if (textValue != null) {
                        Matcher matcher = NUMBER_PATTERN.matcher(textValue);
                        if (matcher.matches()) {
                            // 是数字当作double处理
                            cell.setCellValue(Double.parseDouble(textValue));
                        } else {
                            HSSFRichTextString richString = new HSSFRichTextString(
                                    textValue);

                            richString.applyFont(font3);
                            cell.setCellValue(richString);
                        }
                    }
                }
            }
        }

        setResponseHeader(response, fileName);
        ServletOutputStream out = response.getOutputStream();
        workbook.write(out);
    }
    /**
     * 导出Excel工具
     *
     * @param fileName  文件名
     * @param sheetName sheet名称
     * @param response  response
     * @param pattern   日期格式化
     * @throws IOException IO异常
     */
    public static <T> void exportObjectExcel(String fileName, String sheetName, String[] headers, List<T> dataList, ExcelInfo<T> iExcelInfo, HttpServletResponse response, String pattern) throws IOException {

        exportExcel(fileName, sheetName, headers, dataList, null, iExcelInfo, response, pattern);
    }

    /**
     * 导出Excel工具,
     *
     * @param fileName  文件名
     * @param sheetName sheet名称
     * @param response  response
     * @param pattern   日期格式化
     * @throws IOException io异常
     */
    public static <T> void exportObjectExcel(String fileName, String sheetName, String[] headers, List<T> dataList, String[] keyList, HttpServletResponse response, String pattern) throws IOException {

        exportExcel(fileName, sheetName, headers, dataList, keyList, new ExcelInfo<T>() {
            @Override
            public Map<String, Object> getRowDataMap(T rowData) {
                return (JSONObject)JSONObject.toJSON(rowData);
            }
        }, response, pattern);
    }

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

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

    public static String getTextObject(Object value, DateTimeFormatter sdf) {
        if (value == null) {
            return "";
        } else if (value instanceof Date) {
            ZoneId zone = ZoneId.systemDefault();
            Date date = (Date) value;
            return sdf.format(date.toInstant().atZone(zone).toLocalDateTime());
        } else if (value instanceof LocalDateTime) {
            return ((LocalDateTime) value).format(sdf);
        } else if (value instanceof BigDecimal) {
            return ((BigDecimal) value).setScale(2, RoundingMode.HALF_UP).toPlainString();
        } else {
            return value.toString();
        }
    }

    /**
     * 设置表格头
     * @param sheet sheet
     * @param headers 标题数组
     */
    private static void setTitle(HSSFSheet sheet, String[] headers) {
        HSSFWorkbook workbook = sheet.getWorkbook();
        HSSFCellStyle style = getHeaderStyle(workbook);
        // 生成一个字体
        HSSFFont font = workbook.createFont();
        font.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
        font.setFontHeightInPoints((short) 12);
        font.setBold(true);
        // 把字体应用到当前的样式
        style.setFont(font);
        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);
        for (short i = 0; i < headers.length; i++) {
            HSSFCell cell = row.createCell(i);
            cell.setCellStyle(style);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            cell.setCellValue(text);
        }
    }

    private static void setPic(HSSFRow hssfRow, Sheet sheet, HSSFPatriarch patriarch, byte[] value, int col, int row) {
        // 有图片时，设置行高为60px;
        hssfRow.setHeightInPoints(60);
        // 设置图片所在列宽度为80px,注意这里单位的一个换算
        sheet.setColumnWidth(col, (short) (35.7 * 80));
        // sheet.autoSizeColumn(i);
        HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0,
                1023, 255, (short) 6, row, (short) 6, row);
        anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
        patriarch.createPicture(anchor, sheet.getWorkbook().addPicture(
                value, HSSFWorkbook.PICTURE_TYPE_JPEG));
    }

    /**
     * 标题的样式
     */
    private static HSSFCellStyle getHeaderStyle(HSSFWorkbook workbook) {
        HSSFPalette customPalette = workbook.getCustomPalette();
        customPalette.setColorAtIndex(HSSFColor.HSSFColorPredefined.TAN.getIndex(), (byte) 0xDD, (byte) 0xEB, (byte) 0xF7);

        HSSFCellStyle cellStyle = workbook.createCellStyle();
        setCellStyle(cellStyle);
        cellStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.TAN.getIndex());
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        return cellStyle;
    }

    public static void setCellStyle(CellStyle cellStyle) {
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);
    }

    public static HSSFCellStyle getCellStyle(HSSFWorkbook workbook) {
        HSSFCellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setVerticalAlignment(VerticalAlignment.TOP);
//        cellStyle.setWrapText(true);
        return cellStyle;
    }

    public static void output(Workbook workbook, String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
        if (workbook instanceof HSSFWorkbook) {
            setResponseHeader(response, fileName);
        } else {
            setXSSFResponseHeader(response, fileName);
        }

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

    public static String encodeURIComponent(String value) {
        try {
            return URLEncoder.encode(value, "UTF-8").replaceAll("\\+", "%20");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Workbook getWorkBook(MultipartFile file) {
        //获得文件名
        String fileName = file.getOriginalFilename();
        //创建Workbook工作薄对象，表示整个excel
        Workbook workbook = null;
        try {
            //获取excel文件的io流
            InputStream is = file.getInputStream();
            //根据文件后缀名不同(xls和xlsx)获得不同的Workbook实现类对象
            if (fileName.endsWith("xls")) {
                //2003
                workbook = new HSSFWorkbook(is);
            } else if (fileName.endsWith("xlsx")) {
                //2007 及2007以上
                workbook = new XSSFWorkbook(is);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return workbook;
    }

    public static String getCellValue(Cell cell) {
        String cellValue = "";
        if (cell == null) {
            return cellValue;
        }
        switch (cell.getCellTypeEnum()) {
            case NUMERIC:
                //数字
                cellValue = stringDateProcess(cell);
                break;
            case STRING:
                //字符串
                cellValue = String.valueOf(cell.getStringCellValue());
                break;
            case BOOLEAN:
                //Boolean
                cellValue = String.valueOf(cell.getBooleanCellValue());
                break;
            case FORMULA:
                //公式
                cellValue = String.valueOf(cell.getCellFormula());
                break;
            case BLANK:
                //空值
                cellValue = "";
                break;
            case ERROR:
                //故障
                cellValue = "非法字符";
                break;
            default:
                cellValue = "未知类型";
                break;
        }
        return cellValue;
    }

    public static String stringDateProcess(Cell cell) {
        String result = new String();
        if (HSSFDateUtil.isCellDateFormatted(cell)) {
            // 处理日期格式、时间格式
            SimpleDateFormat sdf = null;
            if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {
                sdf = new SimpleDateFormat("HH:mm");
            } else {// 日期
                sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            }
            Date date = cell.getDateCellValue();
            result = sdf.format(date);
        } else if (cell.getCellStyle().getDataFormat() == 58) {
            // 处理自定义日期格式：m月d日(通过判断单元格的格式id解决，id的值是58)
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            double value = cell.getNumericCellValue();
            Date date = org.apache.poi.ss.usermodel.DateUtil
                    .getJavaDate(value);
            result = sdf.format(date);
        } else {
            double value = cell.getNumericCellValue();
            CellStyle style = cell.getCellStyle();
            DecimalFormat format = new DecimalFormat();
            String temp = style.getDataFormatString();
            // 单元格设置成常规
            if (temp.equals("General")) {
                format.applyPattern("#");
            }
            result = format.format(value);
        }

        return result;
    }

    /**
     * 解析上传的excel， 默认只解析第一张Sheet
     *
     * @param file     excel
     * @param startRow 数据开始行
     * @return List<String [ ]>
     * @throws IOException
     */
    public static List<String[]> getExcelData(MultipartFile file, int startRow) throws IOException {
        int resultSize = 0;
        ArrayList<String[]> resultData = new ArrayList<>(resultSize);
        if (!checkFile(file)) {
            return resultData;
        }
        //获得Workbook工作薄对象
        Workbook workbook = getWorkBook(file);
        if (workbook != null) {
            //获取第一张sheet工作表
            Sheet sheet = workbook.getSheetAt(0);
            if (sheet == null) {
                return resultData;
            }
            // 重新初始化List结果大小
            resultSize = sheet.getLastRowNum() + 1;
            //获得当前sheet的开始行
            int firstRowNum = sheet.getFirstRowNum();
            //获得当前sheet的结束行
            int lastRowNum = sheet.getLastRowNum();
            //循环除了startRow的所有行,如果要循环除第一行以外的就firstRowNum+1
            for (int rowNum = firstRowNum + startRow; rowNum <= lastRowNum; rowNum++) {
                //获得当前行
                Row row = sheet.getRow(rowNum);
                if (rowIsEmpty(row)) {
                    break;
                }
                //获得当前行的开始列
                int firstCellNum = row.getFirstCellNum();
                //获得当前行的列数
                int lastCellNum = row.getLastCellNum();
                String[] cells = new String[lastCellNum];
                //循环当前行
                for (int cellNum = firstCellNum; cellNum < lastCellNum; cellNum++) {
                    Cell cell = row.getCell(cellNum);
                    cells[cellNum] = getCellValue(cell);
                }
                resultData.add(cells);
            }
            workbook.close();
        }
        return resultData;
    }
    public static boolean rowIsEmpty(Row row) {
        if (null == row) {
            return true;
        }
        for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {
            Cell cell = row.getCell(c);
            if (cell != null) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查文件格式
     *
     * @param file
     * @throws IOException
     */
    public static boolean checkFile(MultipartFile file) throws IOException {
        if (null == file) {
            return false;
        }
        //获得文件名
        String fileName = file.getOriginalFilename();
        //判断文件是否是excel文件
        if (!fileName.endsWith("xls") && !fileName.endsWith("xlsx")) {
            return false;
        }
        return true;
    }
}

