package com.yonge.toolset.utils.easyexcel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils;
import org.apache.commons.codec.Charsets;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

/**
 * 导入数据工具包
 * <p>
 * 1.导入默认行数为maxRows-10000行
 * <p>
 * 2.可以在Class实体类中使用Validation相关AOP注解
 * <p>
 * 例如：
 * <p>
 * 在多个字段上添加@NotBlank("xx不能为空！") 注解，
 * 若多次触发该注解，<p>多个错误信息会用逗号拼接再放入 ExcelDataReaderProperty.errorMessage字段中
 * <p>
 *
 * @author hgw
 * Created by 2021-07-22
 */
public class ExcelUtils {
    private static final Logger log = LoggerFactory.getLogger(ExcelUtils.class);

    private static final int maxRows = 10000;

    public static <T> ExcelDataReader<T> getReader(Class<T> clazz, HttpServletRequest req) {
        return getReader(clazz, req, maxRows);
    }

    public static <T> ExcelDataReader<T> getReader(Class<T> clazz, HttpServletRequest req, int maxRows) {
        StandardMultipartHttpServletRequest request = (StandardMultipartHttpServletRequest) req;
        MultipartFile excel = request.getFile("file");
        return getExcelDataReader(clazz, maxRows, excel);
    }

    public static <T> ExcelDataReader<T> getReader(Class<T> clazz, MultipartFile excel) {
        return getReader(clazz, excel, maxRows);
    }

    public static <T> ExcelDataReader<T> getReader(Class<T> clazz, MultipartFile excel, int maxRows) {
        return getExcelDataReader(clazz, maxRows, excel);
    }

    //导入数据
    private static <T> ExcelDataReader<T> getExcelDataReader(Class<T> clazz, int maxRows, MultipartFile excel) {
        //校验数据
        ExcelTypeEnum readEnum = checkAndGetExcelType(excel);
        //读取数据
        ExcelDataReader<T> reader = new ExcelDataReader<>(maxRows, excel.getOriginalFilename());
        try {
            EasyExcel.read(excel.getInputStream(), clazz, reader)
                    .excelType(readEnum)
                    .doReadAll();
        } catch (Exception e) {
            throw new RuntimeException("导入数据异常！", e.getCause());
        }
        return reader;
    }

    //校验数据有效性并获导入格式
    private static ExcelTypeEnum checkAndGetExcelType(MultipartFile excel) {
        if (Objects.isNull(excel)) {
            throw new RuntimeException("请选择一份需要导入的文件！");
        }
        if (excel.isEmpty()) {
            throw new RuntimeException("导入的文件是空的！");
        }
        if (StringUtils.isBlank(excel.getOriginalFilename())) {
            throw new RuntimeException("文件名不能为空！");
        }
        String[] split = excel.getOriginalFilename().split("\\.");
        if (split.length != 2) {
            throw new RuntimeException("文件名不规范！示例：文件名.xlsx 或 文件名.xls");
        }
        String excelType = split[1];
        ExcelTypeEnum xlsxTypeEnum = ExcelTypeEnum.XLSX;
        ExcelTypeEnum xlsTypeEnum = ExcelTypeEnum.XLS;
        ExcelTypeEnum readEnum;
        if (xlsxTypeEnum.getValue().equalsIgnoreCase("." + excelType)) {
            readEnum = xlsxTypeEnum;
        } else if (xlsTypeEnum.getValue().equalsIgnoreCase("." + excelType)) {
            readEnum = xlsTypeEnum;
        } else {
            throw new RuntimeException("只能上传[ .xlsx 或 .xls ]格式的文件！");
        }
        return readEnum;
    }

    public static <T> void exportExcel(List<T> data, String fileName) {
        exportExcel(data, fileName, "sheet1");
    }

    /**
     * 导出数据
     * <p>-导出默认.xlsx
     * <p>-传入的导出文件名不能有符号
     *
     * @param data     需要导出的数据
     * @param fileName 导出数据的名称
     * @param <T>      导出数据实体类-需要@ExcelProperty标签
     */
    public static <T> void exportExcel(List<T> data, String fileName, String sheetName) {
        HttpServletResponse response = Optional.ofNullable(RequestContextHolder.getRequestAttributes())
                .map(r -> (ServletRequestAttributes) r)
                .map(ServletRequestAttributes::getResponse)
                .orElse(null);
        if (Objects.isNull(response)) {
            return;
        }

        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding(Charsets.UTF_8.name());
            fileName = URLEncoder.encode(fileName, Charsets.UTF_8.name());
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ExcelTypeEnum.XLS.getValue());
            if (!CollectionUtils.isEmpty(data)) {
                EasyExcel.write(response.getOutputStream(), data.get(0).getClass()).excelType(ExcelTypeEnum.XLS).sheet(sheetName).doWrite(data);
            } else {
                throw new RuntimeException("没有数据导出！");
            }
        } catch (IOException e) {
            throw new RuntimeException("导出数据异常！", e.getCause());
        }
    }
}
