package com.cool.store.utils.easyExcel;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;

import com.cool.store.constants.CommonConstants;
import com.cool.store.handler.CenterAlignHandler;
import com.cool.store.handler.ImplProgressReportSheetWriteHandler;
import com.cool.store.mapper.ImportTaskMapper;
import com.cool.store.oss.OssClientService;
import com.cool.store.utils.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;

@Slf4j
@Component
public class EasyExcelUtil {

    private static final String EXCEL_SUFFIX = ".xlsx";
    private static final String CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    @Value("${mybatis.configuration.variables.enterpriseId}")
    private String eid;
    @Resource
    private OssClientService ossClientService;
    @Resource
    private ImportTaskMapper importTaskMapper;

    /**
     * 导出excel
     *
     * @param fileName 保存文件的标题
     * @param head     保存excel对象的实体类
     * @param list     需要保存的数据列表
     * @throws IOException 异常捕获
     */
    public String exportExcel( Class head, List list, Set<String> set, String sheetName, String fileName) throws Exception {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        if (set == null) {
            EasyExcel.write(outputStream, head)
                    .autoCloseStream(true)
                    .registerWriteHandler(new SimpleRowHeightStyleStrategy((short)25,(short)25))
                    .sheet(sheetName)
                    .doWrite(list);
        } else {
            EasyExcel.write(outputStream, head).autoCloseStream(true).includeColumnFiledNames(set).sheet(sheetName)
                    .doWrite(list);
        }
        byte[] bytes = outputStream.toByteArray();
        long size = bytes.length;
        InputStream is = new ByteArrayInputStream(bytes);
        if (StringUtils.isNotBlank(fileName) && fileName.contains(".")) {
            fileName = fileName.substring(0, fileName.lastIndexOf("."));
        }
        String file = getUploadPath(eid) + fileName + "_" + UUIDUtils.get32UUID() + EXCEL_SUFFIX;
        return ossClientService.putObject(file, is, size, CONTENT_TYPE);

    }

    //表头从第二行开始，第一行显示日期
    public String exportExcelSpecial( Class head, List list, Set<String> set, String sheetName, String fileName,String firstTitle,String startTime,String endTime) throws Exception {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        if (set == null) {
            EasyExcel.write(outputStream)
                    .head(head)
                    .autoCloseStream(true)
                    .registerWriteHandler( new ImplProgressReportSheetWriteHandler(firstTitle+" "+startTime+" 至 "+endTime))
                    .registerWriteHandler(new CenterAlignHandler())
                    .sheet(sheetName)
                    .useDefaultStyle(false).relativeHeadRowIndex(2)
                    .doWrite(list);
        } else {
            EasyExcel.write(outputStream, head).autoCloseStream(true).includeColumnFiledNames(set).sheet(sheetName)
                    .doWrite(list);
        }
        byte[] bytes = outputStream.toByteArray();
        long size = bytes.length;
        InputStream is = new ByteArrayInputStream(bytes);
        if (StringUtils.isNotBlank(fileName) && fileName.contains(".")) {
            fileName = fileName.substring(0, fileName.lastIndexOf("."));
        }
        String file = getUploadPath(eid) + fileName + "_" + UUIDUtils.get32UUID() + EXCEL_SUFFIX;
        return ossClientService.putObject(file, is, size, CONTENT_TYPE);

    }

    private String getUploadPath(String eid) {
        String time = DateUtil.format(new Date(), "yyMM");
        return "eid" + "/" + eid + "/" + time + "/";
    }

    /**
     * 分批次导出并上传 OSS
     *
     * @param head      数据模型类
     * @param provider  数据提供者回调
     * @param sheetName Sheet名称
     * @param fileName  文件名称
     * @return OSS URL
     */
    public <T> String exportExcelInBatches(Class<T> head, BatchDataProvider<T> provider, String sheetName, String fileName) throws Exception {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        InputStream is = null;
        ExcelWriter excelWriter;
        try {
            excelWriter = EasyExcel.write(outputStream, head)
                    .autoCloseStream(false) // 手动控制流
                    .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 25, (short) 25))
                    .build();

            WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();

            int pageNum = 1, pageSize = CommonConstants.BATCH_SIZE;
            boolean hasNext = true;
            while (hasNext) {
                List<T> data = provider.nextBatch(pageNum, pageSize);
                if (CollectionUtils.isEmpty(data)) {
                    break;
                }
                hasNext = data.size() == pageSize;
                excelWriter.write(data, writeSheet);
                log.info("Excel批次导出：已写入第 {} 页，本页 {} 条数据", pageNum, data.size());

                pageNum++;
            }
            excelWriter.finish();

            byte[] bytes = outputStream.toByteArray();
            is = new ByteArrayInputStream(bytes);

            if (StringUtils.isNotBlank(fileName) && fileName.contains(".")) {
                fileName = fileName.substring(0, fileName.lastIndexOf("."));
            }
            String file = getUploadPath(eid) + fileName + "_" + UUIDUtils.get32UUID() + EXCEL_SUFFIX;
            return ossClientService.putObject(file, is, (long) bytes.length, CONTENT_TYPE);
        } finally {
            outputStream.close();
            if (Objects.nonNull(is)) {
                is.close();
            }
        }
    }
}

