package com.hz.pm.api.common.util;

import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.model.ApiResponse;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdDateUtils;
import com.ningdatech.basic.util.StrPool;
import com.hz.pm.api.common.model.constant.CommonConst;
import com.hz.pm.api.common.enumeration.ExportOptionEnum;
import com.hz.pm.api.common.model.entity.ExcelExportWriter;
import com.hz.pm.api.projectlib.model.entity.Project;
import com.wflow.workflow.bean.vo.ProcessInstanceVo;
import com.wflow.workflow.bean.vo.ProcessTaskVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.http.HttpStatus;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.function.BiConsumer;

/**
 * <p>
 * ExcelDownUtil
 * </p>
 *
 * @author WendyYang
 * @since 00:48 2022/11/5
 */
@Slf4j
public class ExcelDownUtil {

    public static Map<String,String> convertMap = Maps.newHashMap();

    static {
        convertMap.put("buildBasis","baseBasisEstablish");
    }

    public static String encodeName(String name) {
        String fileName;
        try {
            fileName = URLEncoder.encode(name, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error("文件名编码异常：", e);
            fileName = UUID.randomUUID().toString().replace("-", "");
        }
        return fileName;
    }

    @SneakyThrows
    private static <T> void down(HttpServletResponse response, T param, BiConsumer<HttpServletResponse, T> consumer) {
        response.setCharacterEncoding("utf-8");
        try {
            consumer.accept(response, param);
        } catch (Exception e) {
            log.error("文件导出失败：", e);
            response.reset();
            response.setContentType(StrPool.CONTENT_TYPE);
            ApiResponse<Void> res = ApiResponse.of(HttpStatus.SC_BAD_REQUEST, "导出失败", null);
            response.setStatus(HttpStatus.SC_BAD_REQUEST);
            response.getWriter().println(JSON.toJSONString(res));
        }
    }

    public static <T> void downXls(HttpServletResponse response, T param, BiConsumer<HttpServletResponse, T> consumer) {
        response.setContentType(ExcelUtil.XLS_CONTENT_TYPE);
        down(response, param, consumer);
    }

    public static <T> void downXlsx(HttpServletResponse response, T param, BiConsumer<HttpServletResponse, T> consumer) {
        response.setContentType(ExcelUtil.XLSX_CONTENT_TYPE);
        down(response, param, consumer);
    }

    public static void setFileName(String fileName, HttpServletResponse response) {
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeName(fileName) + ".xls");
    }

    public static void excelExportFile(HttpServletResponse response, ExcelExportWriter excelExport) {
        try {
            if (Objects.isNull(excelExport)) {
                throw new BizException("导出失败！");
            }
            setExportResponseHeader(excelExport.getFileName(), response);

            ExcelWriter writer;
            //是否启用头部属性、头部属性类不能为空
            if (Objects.nonNull(excelExport.getHeadPropertyFlag()) && excelExport.getHeadPropertyFlag() && Objects.nonNull(excelExport.getHeadPropertyClass())) {
                writer = EasyExcel.write(response.getOutputStream(), excelExport.getHeadPropertyClass()).build();
            } else {
                writer = EasyExcel.write(response.getOutputStream()).build();
            }
            int sheetNum = 0;
            if (CollectionUtils.isNotEmpty(excelExport.getSheets())) {
                sheetNum = excelExport.getSheets().size();
            } else if (CollectionUtils.isNotEmpty(excelExport.getHeads())) {
                sheetNum = excelExport.getHeads().size();
            } else if (CollectionUtils.isNotEmpty(excelExport.getDatas())) {
                sheetNum = excelExport.getDatas().size();
            }

            if (sheetNum == 0) {
                sheetNum = 1;
            }

            for (int i = 0; i < sheetNum; i++) {
                WriteSheet sheet = EasyExcel.writerSheet(i).automaticMergeHead(false).build();
                if (CollectionUtils.isNotEmpty(excelExport.getSheets())) {
                    sheet.setSheetName(excelExport.getSheets().get(i));
                }
                if (CollectionUtils.isNotEmpty(excelExport.getHeads())) {
                    sheet.setHead(excelExport.getHeads().get(i));
                }

                if (CollectionUtils.isNotEmpty(excelExport.getDatas())) {
                    writer.write((Collection<?>) ((List) excelExport.getDatas()).get(i), sheet);
                } else {
                    writer.write((Collection<?>) null, sheet);
                }
            }
            // 最后 finish
            writer.finish();
            writer.close();
        } catch (Exception e) {
            log.error("export file error!", e);
            throw new BizException("导出失败！");
        }
    }

    public static void setExportResponseHeader(String fileName, HttpServletResponse response) throws UnsupportedEncodingException {
        // 设置响应头和保存文件名
        response.setContentType(ExcelUtil.XLS_CONTENT_TYPE);
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeName(fileName) + ".xls");
    }

    public static List<List<String>> getTaskExportDatas(List<ExportOptionEnum> columnList, List<ProcessTaskVo> taskVoList, Map<String, Project> projectInfoMap) {

        // 表体行数据集合
        List<List<String>> rowList = Lists.newArrayList();
        for (ExportOptionEnum column : columnList) {
            List<String> columnValues = Lists.newArrayList();
            columnValues.add(column.getDesc());
            taskVoList.forEach(taskVo -> {
                Project project = projectInfoMap.get(taskVo.getInstanceId());
                String s = JSON.toJSONString(project);
                JSONObject jsonObject = JSON.parseObject(s);
                String columnValue;
                if (column.name().equals(ExportOptionEnum.processStatusName.name())) {
                    columnValue = taskVo.getStatus();
                } else if (column.name().equals(ExportOptionEnum.processLaunchTime.name())) {
                    columnValue = NdDateUtils.format(taskVo.getCreateTime(), "yyyy-MM-dd HH:mm");
                } else if (column.name().equals(ExportOptionEnum.processHandleTime.name())) {
                    columnValue = NdDateUtils.format(taskVo.getTaskEndTime(), "yyyy-MM-dd HH:mm");
                } else {
                    columnValue = String.valueOf(jsonObject.get(column.toString()));
                }
                columnValues.add(columnValue);
            });
            rowList.add(columnValues);
        }
        return rowList;
    }


    public static List<List<String>> getInstExportDatas(List<ExportOptionEnum> columnList, List<ProcessInstanceVo> instanceVoList, Map<String, Project> projectInfoMap) {

        // 表体行数据集合
        List<List<String>> rowList = Lists.newArrayList();
        for (ExportOptionEnum column : columnList) {
            List<String> columnValues = Lists.newArrayList();
            columnValues.add(column.getDesc());
            instanceVoList.forEach(instanceVo -> {
                Project project = projectInfoMap.get(instanceVo.getInstanceId());
                String s = JSON.toJSONString(project);
                JSONObject jsonObject = JSON.parseObject(s);
                String columnValue;
                if (column.name().equals(ExportOptionEnum.processStatusName.name())) {
                    columnValue = instanceVo.getStatus();
                } else if (column.name().equals(ExportOptionEnum.processLaunchTime.name())) {
                    columnValue = NdDateUtils.format(instanceVo.getStartTime(), "yyyy-MM-dd HH:mm");
                } else {
                    columnValue = String.valueOf(jsonObject.get(column.toString()));
                }
                columnValues.add(columnValue);
            });
            rowList.add(columnValues);
        }
        return rowList;
    }


    public static List<List<String>> getProjectExportDatas(List<ExportOptionEnum> columnList, List<Project> projects) {

        // 表体行数据集合
        List<List<String>> rowList = Lists.newArrayList();
        for (ExportOptionEnum column : columnList) {
            List<String> columnValues = Lists.newArrayList();
            if(Objects.isNull(column)){
                continue;
            }
            String desc = column.getDesc();
            if (Objects.nonNull(desc)) {
                columnValues.add(desc);
            }
            projects.forEach(project -> {
                String s = JSON.toJSONString(project);
                JSONObject jsonObject = JSON.parseObject(s);
                String columnValue;
                if (ExportOptionEnum.preliminaryPlanFile.equals(column)
                        || ExportOptionEnum.supportingMaterialsFile.equals(column)) {
                    String fileStr = jsonObject.getString(column.toString());
                    if (Objects.isNull(fileStr) || CommonConst.NULL.equals(fileStr)) {
                        return;
                    }
                    List<JSONObject> fileArray = JSON.parseArray(fileStr, JSONObject.class);
                    List<String> nameList = CollUtils.fieldList(fileArray, w -> w.getString(CommonConst.FILE_NAME));
                    columnValue = String.join(StrPool.COMMA, nameList);
                } else {
                    //强转列
                    if(convertMap.containsKey(column.toString())){
                        columnValue = jsonObject.getString(convertMap.get(column.toString()));
                    }else{
                        columnValue = jsonObject.getString(column.toString());
                    }
                }
                if (Objects.isNull(columnValue) || CommonConst.NULL.equals(columnValue)) {
                    columnValue = "";
                }
                columnValues.add(columnValue);
            });
            rowList.add(columnValues);
        }
        return rowList;
    }

}
