package com.qmth.paper.library.common.util;

import com.qmth.paper.library.common.contant.SystemConstant;
import com.qmth.paper.library.common.enums.ExceptionResultEnum;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description: 转换工具类
 * @Author: CaoZixuan
 * @Date: 2021-04-14
 */

@Component
public class ConvertUtil {
    private final static Logger log = LoggerFactory.getLogger(ConvertUtil.class);

    // inputStream转outputStream
    public static ByteArrayOutputStream parse(final InputStream in) throws Exception {
        final ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        int ch;
        while ((ch = in.read()) != -1) {
            swapStream.write(ch);
        }
        return swapStream;
    }

    // outputStream转inputStream
    public static ByteArrayInputStream parse(final OutputStream out) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos = (ByteArrayOutputStream) out;
        return new ByteArrayInputStream(baos.toByteArray());
    }

    public static void inputStream2File(InputStream is, File file) throws IOException {
        OutputStream os = null;
        try {
            os = new FileOutputStream(file);
            int len = 0;
            byte[] buffer = new byte[8192];

            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
        } finally {
            os.close();
            is.close();
        }
    }

    /**
     * 转换，解析时间
     *
     * @param date 日期(考试日期，必须是同一天     example: 2021-04-13)
     * @param time 时间(考试时间，必须使用‘-’隔开  example: 18:00-20:00)
     * @return 开始时间和结束时间键值对(" startTime " : 1618308000000, " endTime " : 1618315200000)
     */
    public static Map<String, Object> analyzeStartAndEndTime(String date, String time) {
        time = time.replaceAll(" ", ""); // 去掉所有空格
        String[] arr = time.split("-");
        if (arr.length != 2) {
            // 不能使用'-'拆分成两个时间的报错
            throw ExceptionResultEnum.ERROR.exception("提供的时间格式异常 【考试时间】:" + time + " 应该使用如下的格式【考试时间】:18:00-20:00");
        }
        String startTimeStr = date + " " + arr[0];
        String endTimeStr = date + " " + arr[1];
        if (Objects.isNull(DateDisposeUtils.parseDate(startTimeStr)) || Objects.isNull(DateDisposeUtils.parseDate(endTimeStr))) {
            throw ExceptionResultEnum.ERROR.exception("提供的日期时间格式异常 \n【考试日期】:" + date + " 应该使用如下的格式【考试日期】:2021-09-01 或 2021/09/01 或 2021.09.01" + "\n【考试时间】:" + time + " 应该使用如下的格式【考试时间】:18:00-20:00");
        }
        long startTime = DateDisposeUtils.parseDate(startTimeStr).getTime();
        long endTime = DateDisposeUtils.parseDate(endTimeStr).getTime();
        if (startTime >= endTime) {
            throw ExceptionResultEnum.ERROR.exception("开始时间要小于结束时间 时间： " + time);
        }

        Map<String, Object> timeMap = new HashMap<>();
        timeMap.put("startTime", startTime);
        timeMap.put("endTime", endTime);
        return timeMap;
    }

    /**
     * 根据开始时间和结束时间解析日期和时间
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 键值对
     */
    public static Map<String, Object> analyzeDateAndTime(Long startTime, Long endTime) {
        String tmpDateStart;
        String tmpDateEnd;
        String tmpTimeStart;
        String tmpTimeEnd;
        String date;
        String time;


        Map<String, Object> map = new HashMap<>();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(startTime));
        tmpDateStart = (new SimpleDateFormat("yyyy-MM-dd")).format(calendar.getTime());
        tmpTimeStart = (new SimpleDateFormat("HH:mm:ss")).format(calendar.getTime());

        calendar.setTime(new Date(endTime));
        tmpDateEnd = (new SimpleDateFormat("yyyy-MM-dd")).format(calendar.getTime());
        tmpTimeEnd = (new SimpleDateFormat("HH:mm:ss")).format(calendar.getTime());

        if (!tmpDateStart.equals(tmpDateEnd)) {
            throw ExceptionResultEnum.ERROR.exception("开始时间和结束时间不在同一天");
        }

        date = tmpDateStart;
        time = tmpTimeStart + " - " + tmpTimeEnd;
        map.put("date", date);
        map.put("time", time);

        return map;
    }


    /**
     * 根据开始时间和结束时间解析日期和时间
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     */
    public static void analyzeAndCompareDateAndTime(Long startTime, Long endTime) {
        String tmpDateStart;
        String tmpDateEnd;

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(startTime));
        tmpDateStart = (new SimpleDateFormat("yyyy-MM-dd")).format(calendar.getTime());

        calendar.setTime(new Date(endTime));
        tmpDateEnd = (new SimpleDateFormat("yyyy-MM-dd")).format(calendar.getTime());

        if (!tmpDateStart.equals(tmpDateEnd)) {
            throw ExceptionResultEnum.ERROR.exception("开始时间和结束时间不在同一天");
        }

        if (startTime >= endTime) {
            throw ExceptionResultEnum.ERROR.exception("开始时间必须小于结束时间");
        }
    }


    /**
     * 解析excel单元格类型
     *
     * @param cell 单元格
     * @return 转换成字符串后的值
     */
    public static String analyzeExcelCellValue(Cell cell) {
        String cellValue;
        CellType cellType = cell.getCellType();
        switch (cellType) {
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    SimpleDateFormat sdf;
                    // 验证short值
                    if (cell.getCellStyle().getDataFormat() == 14) {
                        sdf = new SimpleDateFormat("yyyy/MM/dd");
                    } else if (cell.getCellStyle().getDataFormat() == 21) {
                        sdf = new SimpleDateFormat("HH:mm:ss");
                    } else if (cell.getCellStyle().getDataFormat() == 22) {
                        sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                    } else {
                        throw new RuntimeException("日期格式错误!!!");
                    }
                    Date date = cell.getDateCellValue();
                    cellValue = sdf.format(date);
                } else {//处理数值格式
                    cell.setCellType(CellType.STRING);
                    cellValue = String.valueOf(cell.getRichStringCellValue().getString());
                }
                break;
            case STRING:
                cellValue = String.valueOf(cell.getStringCellValue());
                break;
            case BOOLEAN:
                cellValue = String.valueOf(cell.getBooleanCellValue());
                break;
            case FORMULA:
                cellValue = String.valueOf(cell.getCellFormula());
                break;
            case BLANK:
                cellValue = null;
                break;
            case ERROR:
                cellValue = "非法字符";
                break;
            default:
                cellValue = "未知类型";
                break;
        }
        return cellValue;
    }

    public static void delFolder(String folderPath) {
        try {
            delAllFile(folderPath); //删除完里面所有内容
            String filePath = folderPath;
            filePath = filePath.toString();
            File myFilePath = new File(filePath);
            myFilePath.delete(); //删除空文件夹
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
        }
    }

    public static void delAllFile(String path) {
        boolean flag = false;
        File file = new File(path);
        if (!file.exists()) {
            return;
        }
        if (!file.isDirectory()) {
            return;
        }
        String[] tempList = file.list();
        File temp = null;
        for (int i = 0; i < Objects.requireNonNull(tempList).length; i++) {
            if (path.endsWith(File.separator)) {
                temp = new File(path + tempList[i]);
            } else {
                temp = new File(path + File.separator + tempList[i]);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
                delFolder(path + "/" + tempList[i]);//再删除空文件夹
                flag = true;
            }
        }
    }

    public File saveLocal(InputStream inputStream, String dirPath) throws IOException {
        File desFile = new File(dirPath);
        if (!desFile.getParentFile().exists()) {
            desFile.getParentFile().mkdirs(); //目标文件目录不存在的话需要创建目录
        }
        byte[] bytes = new byte[1024]; // 开辟一个拷贝缓冲区
        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(desFile);
            int length;
            while ((length = inputStream.read(bytes)) != -1) { //当读到尽头后，返回值为-1这个时候停止输出，拷贝结束
                outputStream.write(bytes, 0, length);
            }
            return desFile;
        } catch (Exception e) {
            throw e;
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }

    /**
     * 判断里面参数只要有一个为空 就是true 全部不为空时 false
     *
     * @param strArr 字符串组
     * @return 全部有值 - false；任意一个为空 - true
     */
    public static boolean strAnyEmpty(String... strArr) {
        if (strArr.length == 0) {
            return true;
        } else {
            for (String str : strArr) {
                if (!SystemConstant.strNotNull(str)) {
                    return true;
                }
            }
            return false;
        }
    }

    public static void outputFile(HttpServletResponse response, InputStream inputStream, String fileName) {
        try {
            byte[] buf = new byte[1024];
            int len = 0;

            String fName = new String(fileName.getBytes(), "ISO-8859-1");

            response.reset();
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment; filename=" + fName);

            OutputStream outStream = response.getOutputStream();

            while ((len = inputStream.read(buf)) > 0) {
                outStream.write(buf, 0, len);
            }

            inputStream.close();
            outStream.close();
        } catch (IOException e) {
            log.error(SystemConstant.LOG_ERROR, e);
        }
    }

    public static void outputFile(HttpServletResponse response, ByteArrayOutputStream baos, String fileName) throws Exception {
        try {
            String fName = URLEncoder.encode(fileName, "UTF-8");

            response.reset();
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment; filename=" + fName);

            OutputStream outStream = response.getOutputStream();
            baos.writeTo(outStream);
            outStream.close();
        } catch (IOException e) {
            throw new Exception("下载失败");
        }
    }

    public static List<File> pdfToImageFile(String sourcePath, String targetPath) throws Exception {
        PDDocument doc = null;
        ByteArrayOutputStream os = null;
        InputStream stream = null;
        OutputStream out = null;
        List<File> fileList = new ArrayList<>();
        try {
            // pdf路径
            stream = new FileInputStream(sourcePath);
            // 加载解析PDF文件
            doc = PDDocument.load(stream);
            PDFRenderer pdfRenderer = new PDFRenderer(doc);
            PDPageTree pages = doc.getPages();
            int pageCount = pages.getCount();
            for (int i = 0; i < pageCount; i++) {
                BufferedImage bim = pdfRenderer.renderImageWithDPI(i, 200);
                os = new ByteArrayOutputStream();
                ImageIO.write(bim, "jpg", os);
                byte[] dataList = os.toByteArray();
                // jpg文件转出路径
                File file = new File(targetPath + "-" + (i + 1) + ".jpg");
                if (!file.getParentFile().exists()) {
                    // 不存在则创建父目录及子文件
                    file.getParentFile().mkdirs();
                    file.createNewFile();
                }
                out = new FileOutputStream(file);
                out.write(dataList);
                fileList.add(file);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (doc != null) {
                doc.close();
            }
            if (os != null) {
                os.close();
            }
            if (stream != null) {
                stream.close();
            }
            if (out != null) {
                out.close();
            }
        }
        return fileList;
    }

    public String randomNumberPrefix(String examShortCode, String courseShortCode, String clazzShortCode, Integer examNumberDigit) {
        if (examNumberDigit < 7) {
            return "";
        } else if (examNumberDigit < 11) {
            return examShortCode;
        } else if (examNumberDigit < 13) {
            return examShortCode + courseShortCode;
        }
        return examShortCode + courseShortCode + clazzShortCode;
    }
}
