package com.sqx.modules.utils.excel;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.sqx.common.exception.SqxException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

/**
 * easyexcel工具类
 * @author codingliang
 * @date 2025-09-16
 */
@Slf4j
public class EasyExcelUtil {

    /**
     * 读取excel文件
     *
     * @param <T>      数据类型
     * @param file     excel文件
     * @param head     列名
     * @param callBack 回调 导入时传入定义好的回调接口，excel数据解析完毕之后监听器将数据传入回调函数
     *                 这样调用工具类时可以通过回调函数获取导入的数据，如果数据量过大可根据实际情况进行分配入库
     */
    public static <T> void readAnalysis(MultipartFile file, Class<T> head, ExcelFinishCallBack<T> callBack) {
        try {
            EasyExcel.read(file.getInputStream(), head, new ExcelDataListener<>(callBack)).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 导出Excel文件
     * @param dataList 数据列表
     * @param clazz 数据类的Class对象
     * @param fileName 文件名（不含后缀）
     * @param sheetName 工作表名称
     * @throws IOException IO异常
     */
    public static <T> void exportExcel(List<T> dataList, Class<T> clazz, String fileName, String sheetName) {
        try {
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (requestAttributes == null) {
                throw new SqxException("无法获取响应对象");
            }
            HttpServletResponse response = requestAttributes.getResponse();

            // 设置响应头
            setResponseHeader(response, fileName);

            ExcelWriterBuilder writerBuilder = EasyExcel.write(response.getOutputStream(), clazz);
            writerBuilder.sheet(sheetName);


            EasyExcel.write(response.getOutputStream(), clazz)
                    .sheet(sheetName)
                    .registerConverter(new LongStringConverter())
                    .doWrite(dataList);
        } catch (IOException e) {
            log.error("Excel导出失败：{}", e.getMessage());
            throw new SqxException("Excel导出失败：" + e.getMessage());
        }
    }

    /**
     * 设置响应头，包括内容类型和文件名
     */
    private static void setResponseHeader(HttpServletResponse response, String fileName) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setCharacterEncoding("UTF-8");

        // 如果文件名为空，使用默认名称
        if (StrUtil.isBlank(fileName)) {
            fileName = "导出数据";
        }
        // 添加时间戳，避免文件名重复
        fileName += "_" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
        // URL编码，避免中文乱码
        String encodedFileName = URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + encodedFileName + ".xlsx");
    }
}
