package com.zzsn.knowbase.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.zzsn.knowbase.entity.KnowledgeExcel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@Slf4j
public class ExcelExportUtil {
    private static final String XLS = "xls";
    private static final String XLSX = "xlsx";
    private static final String SPLIT = ".";

    /**
     * 读取excel数据
     *
     * @param firstRow  第一行有用数据(0表示第一行)
     * @param columnNum 有用数据的总列数
     * @return java.util.List<java.util.List < java.lang.String>>
     */
    public static List<List<String>> readExcel(InputStream inputStream, Integer firstRow, Integer columnNum) throws Exception {
        List<List<String>> dataList = new ArrayList<>();
        //获取整个excel
        XSSFWorkbook hb = new XSSFWorkbook(inputStream);
        int sheets = hb.getNumberOfSheets();
        for (int i = 0; i < sheets; i++) {
            XSSFSheet sheet = hb.getSheetAt(i);
            //第一行
            int firstRowNum = sheet.getFirstRowNum();
            //最后一行
            int lastRowNum = sheet.getPhysicalNumberOfRows();
            for (int j = firstRowNum + firstRow; j < lastRowNum; j++) {
                //获取行
                XSSFRow row = sheet.getRow(j);
                if (row != null) {
                    List<String> list = new ArrayList<>();
                    for (int m = 0; m < columnNum; m++) {
                        String data = ExcelExportUtil.getValue(row.getCell(m)).trim();
                        list.add(data);
                    }
                    dataList.add(list);
                }
            }
        }

        return dataList;
    }

    public static String getValue(XSSFCell xssfCell) {
        if (xssfCell == null || xssfCell.toString().trim().equals("")) {
            return "";
        }
        int cellType = xssfCell.getCellType();
        if (cellType == HSSFCell.CELL_TYPE_NUMERIC) {
            if (HSSFDateUtil.isCellDateFormatted(xssfCell)) {
                return TimeUtil.getDateString(xssfCell.getDateCellValue());
            } else {
                //防止数字变成科学计数法的形式
                DecimalFormat df = new DecimalFormat("0");
                return df.format(xssfCell.getNumericCellValue());
            }
        } else {
            return xssfCell.getStringCellValue();
        }
    }

    public static File getFileDir() {
        // 构建上传文件的存放 "文件夹" 路径
        String fileDirPath = new String("src/main/resources/static/uploadFiles" );
        File fileDir = new File(fileDirPath);
        if (!fileDir.exists()) {
            // 递归生成文件夹
            fileDir.mkdirs();
        }
        return fileDir;
    }


    /**
     * 导出
     * @param data
     * @param sheetName
     * @param filePath
     * @param clazz
     * @throws Exception
     */
    public static Boolean writeExcelFront(List data, String sheetName, String filePath, Class clazz) throws Exception {
        //表头样式
        System.out.println("开始写入");
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //内容样式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //设置内容靠左对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        int total = data.size();//总数
        int max = 50000;//每sheet页允许最大数
        int avg = total / max;//sheet页个数
        ExcelWriter excelWriter= EasyExcel.write(filePath, clazz).excelType(ExcelTypeEnum.XLSX).registerWriteHandler(horizontalCellStyleStrategy).build();
        try{
            for (int j = 0; j < avg + 1; j++) {
                String sheetnames=sheetName;
                int num = j * max;
                List dataList1 = new ArrayList<>();
                if (StringUtils.isNotBlank(sheetnames)) {

                    sheetnames = sheetnames + (j + 1);
                } else {
                    sheetnames = j + "";
                }
                for (int n = num; n < total; n++) {//n即为每个sheet页应该开始的数
                    if(n>=num+50000){
                        break;
                    }

                    dataList1.add(data.get(n));//从总的list数据里面取出该处于哪个sheet页的数据，然后加进exportList，exportList即为当前sheet页应该有的数据

                }
                WriteSheet writeSheet = EasyExcel.writerSheet(j, sheetnames).build();
                excelWriter.write(dataList1,writeSheet);
            }
        }finally {
            // 千万别忘记finish 会帮忙关闭流
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
        System.out.println("写入完成");
        return true;
    }

    public static void download(HttpServletResponse response, String filePath, boolean delete) throws UnsupportedEncodingException {
        File file = new File(filePath);
        if (file.exists()) {
            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(file.getName(), "utf8"));
            //加上设置大小 下载下来的excel文件才不会在打开前提示修复
            response.addHeader("Content-Length", String.valueOf(file.length()));
            byte[] buffer = new byte[1024];
            //输出流
            OutputStream os = null;
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            try {
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                os = response.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer);
                    os.flush();
                    i = bis.read(buffer);
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (os != null) {
                        os.close();
                    }
                    if (fis != null) {
                        fis.close();
                    }
                    if (bis != null) {
                        bis.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (delete) {
                //文件下载结束后，删除上传到项目的文件
                file.delete();
            }
        }
    }

    /**
     * 获取Excel表头信息
     * @param workbook
     * @return
     */
    public static List<String> getSheetTitles(Workbook workbook) {
        // 拿第一个sheet表
        Sheet sheet = workbook.getSheetAt(0);
        // 校验sheet是否合法
        if (Objects.isNull(sheet)) {
            return null;
        }
        // 获取第一行数据（假如第一行就是列名）
        Row sheetTitleRow = sheet.getRow(sheet.getFirstRowNum());
        // 取出最后一列
        short lastCellNum = sheetTitleRow.getLastCellNum();
        List<String> sheetTitleList = new LinkedList<>();
        for (int i = 0; i < lastCellNum; i++) {
            // 取出每一列的名
            String cellValue = sheetTitleRow.getCell(i).getStringCellValue();
            sheetTitleList.add(cellValue);
        }
        return sheetTitleList;
    }

    /**
     * 获取Excel表信息
     * @param file
     * @return
     */
    public static Workbook getWorkbook(MultipartFile file) {
        Workbook workbook = null;
        try {
            // 获取Excel后缀名
            String fileName = file.getOriginalFilename();
            if (StringUtils.isEmpty(fileName) || fileName.lastIndexOf(SPLIT) < 0) {
                log.warn("解析Excel失败，因为获取到的Excel文件名非法！");
                return null;
            }
            String fileType = fileName.substring(fileName.lastIndexOf(SPLIT) + 1);
            // 获取Excel工作簿
            if (fileType.equalsIgnoreCase(XLS)) {
                workbook = new HSSFWorkbook(file.getInputStream());
            } else if (fileType.equalsIgnoreCase(XLSX)) {
                workbook = new XSSFWorkbook(file.getInputStream());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return workbook;
    }


    //多个sheet
    public static void exportExcelData(XSSFWorkbook workbook, int sheetNum, List<String> keyList, List<List<String>> rows, String sheetName) {
        Sheet sheet = workbook.createSheet();
        //多个sheet
        workbook.setSheetName(sheetNum,sheetName);
        sheet.setDefaultColumnWidth(20);
        sheet.setDefaultRowHeight((short) 400);
        XSSFCellStyle titleStyle = ExcelExportUtil.getHeaderStyle(workbook);
        XSSFCellStyle rowStrStyle = ExcelExportUtil.getRowStrStyle(workbook);
        // 产生表格标题行
        Row row = sheet.createRow(0);
        row.setHeight((short) 400);
        Cell cell;
        List<String> colData = new ArrayList<>(keyList);
        for (int i = 0; i < colData.size(); i++) {
            cell = row.createCell(i, CellType.STRING);
            cell.setCellStyle(titleStyle);
            cell.setCellValue(new XSSFRichTextString(colData.get(i)));
        }
        // 数据行
        for (int m = 0; m < rows.size(); m++) {
            List<String>  rowData = rows.get(m);
            row = sheet.createRow(m + 1);
            row.setHeight((short) 400);
            int i=0;
            for (String rowDatum : rowData) {
                createCell(rowStrStyle, row, i, rowDatum);
                i++;
            }
        }
    }
    private static void createCell(XSSFCellStyle rowStrStyle, Row row, int index , String value){
        Cell cell = row.createCell(index, CellType.STRING);
        cell.setCellStyle(rowStrStyle);
        cell.setCellValue(value);
    }
    /**
     * 获取标题栏样式
     *
     * @param workbook
     * @return
     */
    private static XSSFCellStyle getHeaderStyle(XSSFWorkbook workbook) {
        // 生成一个样式
        XSSFCellStyle style = workbook.createCellStyle();
        // 设置这些样式
        style.setFillForegroundColor(IndexedColors.SKY_BLUE.index);
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setAlignment(HorizontalAlignment.CENTER);
        // style.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00"));
        // 生成一个字体
        XSSFFont font = workbook.createFont();
        font.setColor(IndexedColors.BLACK.index);
        font.setFontHeightInPoints((short) 9);
        // 把字体应用到当前的样式
        style.setFont(font);
        return style;
    }
    /**
     * 获取字符串型内容栏样式
     *

     * @return
     */
    private static XSSFCellStyle getRowStrStyle(XSSFWorkbook workbook) {
        // 生成一个样式
        XSSFCellStyle style = workbook.createCellStyle();
        // 设置这些样式
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setAlignment(HorizontalAlignment.CENTER);
        // 生成一个字体
        XSSFFont font = workbook.createFont();
        font.setColor(IndexedColors.BLACK.index);
        font.setFontHeightInPoints((short) 9);
        font.setBold(true);
        // 把字体应用到当前的样式
        style.setFont(font);
        return style;
    }
}
