package com.emergency.avenue.storage.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.emergency.avenue.admin.exception.MyCustomException;
import com.emergency.avenue.admin.exception.MyExceptionMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ClassUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @program: report-java
 * @author: duhuajie
 * @create: 2024-04-15
 * @description:
 *      文件导出生成相关工具类
 */
@Slf4j
public class MyFileUtil {

    public static final String EXCEL_PATH = "file" + File.separator + "excel" + File.separator;
    /**
     *  获取模板文件路径，基于项目路径
     * @return 文件路径
     */
    public static String getXlsPath() {
        return rootPath() + "file" + File.separator + "excel" + File.separator;
    }
    public static String rootPath() {
        return MyFileUtil.class.getResource("/").getPath() + File.separator;
    }
    /**
     * 根据模板生成Excel文件 - 和上面一样，这个多一个list
     *
     * @param response 返回文件流
     * @param fileName 文件名  a.xlsx
     * @param templateFile   模板文件名 t.xlsx
     * @param firstIndex   两行相同数据合并单元格，如果ABC列需要合并，传3
     * @param strnumToNumColumnIndex 有的数字传的string类型，需要把单元格格式改成数字格式，比如AB列需要改成数字格式，传0，1
     * @param list0,list1    多个list 第二个list不配置创建新行 list0 必填
     */
    public static <T1,T2> void listToExcel(HttpServletResponse response,String fileName, String templateFile, int firstIndex, List<Integer> strnumToNumColumnIndex,
                                              List<T1> list0, List<T2> list1) {
        listToExcel(response,fileName, templateFile, firstIndex,strnumToNumColumnIndex, list0, list1,null);
    }


    /**
     * 根据模板生成Excel文件 - 和上面一样，这个多一个list
     *
     * @param response 返回文件流
     * @param fileName 文件名  a.xlsx
     * @param templateFile   模板文件名 t.xlsx
     * @param firstIndex   两行相同数据合并单元格，如果ABC列需要合并，传3
     * @param strnumToNumColumnIndex 有的数字传的string类型，需要把单元格格式改成数字格式，比如AB列需要改成数字格式，传0，1
     * @param list0,list1    多个list 第二个list不配置创建新行
     */
    public static <T1,T2,T3> void listToExcel(HttpServletResponse response, String fileName,String templateFile, int firstIndex, List<Integer> strnumToNumColumnIndex,
                                              List<T1> list0, List<T2> list1, List<T3> list2) {
        try{
            // 这里是设置单元格自动换行
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            contentWriteCellStyle.setWrapped(true);
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(null, contentWriteCellStyle);

            InputStream tem = ClassUtils.getDefaultClassLoader().getResourceAsStream(EXCEL_PATH + templateFile);
            // 读模板，写文件
            ExcelWriter excelWriter = EasyExcel.write(getOutputStream(fileName,response))
                    // 注入处理器 合并单元格的 可以注册到下面 sheet 上
                    .registerWriteHandler(new MyExcelMergeCellHandler(firstIndex,strnumToNumColumnIndex))
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    .withTemplate(tem).build();

            // 创建writeSheet
            WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
            // 填写配置，forceNewRow true表示自动创建一行，后面的数据后移
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            //填写数据 name是模板key  {a.name}
            // 多个list，传入标识符key 和list

            if(list0 != null && !list0.isEmpty()){
                excelWriter.fill(new FillWrapper("list0",list0), fillConfig, writeSheet);
            }
            if(list1 != null && !list1.isEmpty()){
                excelWriter.fill(new FillWrapper("list1",list1), writeSheet);
            }
            if(list2 != null && !list2.isEmpty()){
                excelWriter.fill(new FillWrapper("list2",list2), writeSheet);
            }
            // 关闭填写
            excelWriter.finish();
        }catch (Exception e){
            log.error("生成 Excel异常", e);
            throw new MyCustomException(MyExceptionMessage.MAKE_EXCEL_ERROR.getMessage());
        }
    }


    /**
     * 导出文件时为Writer生成OutputStream.
     *
     * @param fileName 文件名
     * @param response response
     * @return ""
     */
    public static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8");
            // 为了解决多浏览器文件名乱码。
            String agent = response.getHeader("USER-AGENT");
            //IE请求头的user-agent信息开始靠近火狐，这里只能比对ie与火狐的agen区分浏览器了
            if (agent != null) {
                if (agent.contains("Mozilla")) {
                    fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1");
                }
            }

            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
            response.setHeader("Pragma", "public");
            response.setHeader("Cache-Control", "no-store");
            response.addHeader("Cache-Control", "max-age=0");
            return response.getOutputStream();
        } catch (IOException e) {
            throw new Exception("导出excel表格失败!", e);
        }
    }

}
