package com.tofly.watermeter.util;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tofly.watermeter.config.MergeCommand;
import com.tofly.watermeter.config.MergeCommand2;
import com.tofly.watermeter.em.Constant;
import com.tofly.watermeter.em.ExcelExportFileTypeEnum;
import lombok.SneakyThrows;
import org.jxls.builder.xls.XlsCommentAreaBuilder;
import org.jxls.command.EachCommand;
import org.jxls.common.Context;
import org.jxls.expression.JexlExpressionEvaluator;
import org.jxls.transform.Transformer;
import org.jxls.transform.poi.PoiTransformer;
import org.jxls.util.JxlsHelper;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * 用于复杂Excel导出；存在合并单元格操作
 *
 * @author FlashWJL
 * @date 2021/10/27 11:32
 */
public class JxlsUtils {
    /**
     * 批注中命令配置
     * 原文链接：https://blog.csdn.net/hezudao0324/article/details/103635959
     */
    static {
        XlsCommentAreaBuilder.addCommandMapping("each", EachCommand.class);
        XlsCommentAreaBuilder.addCommandMapping("merge", MergeCommand.class);
        XlsCommentAreaBuilder.addCommandMapping("mg", MergeCommand2.class);
    }

    /**
     *
     * @param excelExportFileTypeEnum 枚举中的模板类型
     * @param model 数据格式
     * @param response 响应
     * @param exportPath 导出路径（就是项目根目录）
     */
    @SneakyThrows(Exception.class)
    public static void exportExcel(ExcelExportFileTypeEnum excelExportFileTypeEnum , Map<String, Object> model , HttpServletResponse response,String exportPath){
        //处理导出数据
        dateTransfer(model , excelExportFileTypeEnum , exportPath);
        //响应下载
        //文件名
        String filename = URLEncoder.encode(excelExportFileTypeEnum.getTemplateFile().substring(1), "UTF-8");
        // 设置响应编码
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/x-download");
        response.setHeader("Content-Disposition", "attachment;filename=" + filename);
        OutputStream outputStream = response.getOutputStream();
        InputStream inputStream = new FileInputStream(exportPath);
        byte[] buffer = new byte[1024];
        int i = -1;
        while ((i = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, i);
        }
        outputStream.flush();
        outputStream.close();
        inputStream.close();
    }

    /**
     * 数据根据模板格式将数据存放到根目录下的一个文件中
     * @param model 原有数据
     * @param excelExportFileTypeEnum 枚举中的模板类型
     * @param exportPath 项目根目录
     */
    @SneakyThrows(Exception.class)
    private static void dateTransfer(Map<String, Object> model,
                                     ExcelExportFileTypeEnum excelExportFileTypeEnum, String exportPath) {
        //模板文件路径
        String s = Constant.DEFAULT_REPORT_EXPORT_FOLDER + excelExportFileTypeEnum.getTemplateFile();
        Resource resource =new ClassPathResource(s);
        InputStream inputStream = resource.getInputStream();
        // 创建文件；之后将下载改文件；就是最终的导出文件；创建文件的主要目的是存放根据模板规定好的数据，就在本项目根目录中创建一个文件；最终会存放按照模板格式的Excel文件数据
        //最后会通过读取该目录下（exportPath）的文件流；然后用响应体的输出流读取这个文件；再下载文件即可
        File exportFile = FileUtil.touch(exportPath);
        // 列表数据将存储到指定的excel文件路径
        OutputStream outputStream = new FileOutputStream(exportPath);
        Context context = PoiTransformer.createInitialContext();
        if (model != null) {
            for (String key : model.keySet()) {
                //处理时间格式:::::::::::不用在这里处理的时间格式了，直接在Excel里面定义时间格式，自定义一个yyyy/m/d ::::::::::在这里处理会出现内存溢出的现象，因为导出数据量多，会对这些数据处理时间格式
//                Object object = JSONObject.parseObject(JSONArray.toJSONStringWithDateFormat(model.get(key), "yyyy-MM-dd") , Object.class);
//                context.putVar(key, object);
                context.putVar(key, model.get(key));
            }
        }
        JxlsHelper jxlsHelper = JxlsHelper.getInstance();
        // 将列表数据按照模板文件中的格式生成
        Transformer transformer = jxlsHelper.createTransformer(inputStream, outputStream);
        //获得配置
        JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator) transformer
                .getTransformationConfig().getExpressionEvaluator();
        //设置静默模式，不报警告
        //evaluator.getJexlEngine().setSilent(true);
        //函数强制，自定义功能
        Map<String, Object> funcs = new HashMap<String, Object>();
        funcs.put("utils", new JxlsUtils());    //添加自定义功能
        evaluator.getJexlEngine();
        //必须要这个，否者表格函数统计会错乱
        jxlsHelper.setUseFastFormulaProcessor(false).processTemplate(context, transformer);
    }

    /**
     * 获取文件
     *
     * @param path
     * @return
     */
    public static File getTemplate(String path) {
        File template = new File(path);
        if (template.exists()) {
            return template;
        }
        return null;
    }

}
