package com.yeejoin.amos.boot.module.jg.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.entity.BaseEntity;
import com.yeejoin.amos.boot.biz.common.excel.ExcelUtil;
import com.yeejoin.amos.boot.biz.common.utils.RequestContextWrapper;
import com.yeejoin.amos.boot.module.jg.api.dto.JgUseRegistrationDto;
import com.yeejoin.amos.boot.module.jg.api.dto.JgUseRegistrationManageDto;
import com.yeejoin.amos.boot.module.jg.api.enums.RegOrgEnum;
import com.yeejoin.amos.boot.module.jg.api.enums.RegTypeEnum;
import com.yeejoin.amos.boot.module.jg.api.mapper.*;
import com.yeejoin.amos.boot.module.jg.api.vo.tableDataExportVo.*;
import com.yeejoin.amos.boot.module.jg.biz.edit.typeHandler.CbDataDictTypeHandler;
import com.yeejoin.amos.boot.module.jg.biz.feign.TcmServiceFeignClient;
import com.yeejoin.amos.boot.module.jg.biz.service.IJgTableDataExportService;
import com.yeejoin.amos.boot.module.jg.biz.utils.DictUtil;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgProjectContraption;
import com.yeejoin.amos.boot.module.ymt.api.mapper.TzBaseEnterpriseInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.TzsUserInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.vo.XianElevatorVo;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.utils.ResponseModel;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * JG列表数据导出实现类
 */
@Slf4j
@Service
public class JgTableDataExportServiceImpl implements IJgTableDataExportService {

    @Autowired
    private JgUseRegistrationManageMapper useRegistrationManageMapper;
    @Autowired
    private JgMaintenanceContractMapper maintenanceContractMapper;
    @Autowired
    private JgInstallationNoticeServiceImpl installationNoticeService;
    @Autowired
    private JgMaintainNoticeServiceImpl maintainNoticeService;
    @Autowired
    private JgReformNoticeServiceImpl reformNoticeService;
    @Autowired
    private JgTransferNoticeServiceImpl transferNoticeService;
    @Autowired
    private JgUseRegistrationMapper registrationMapper;
    @Autowired
    private JgChangeRegistrationUnitMapper changeRegistrationUnitMapper;
    @Autowired
    private JgChangeRegistrationReformMapper changeRegistrationReformMapper;
    @Autowired
    private JgEnableDisableMapper enableDisableMapper;
    @Autowired
    private JgScrapCancelServiceImpl scrapCancelService;
    @Autowired
    private JgChangeRegistrationTransferMapper changeRegistrationTransferMapper;
    @Autowired
    private JgChangeRegistrationNameMapper changeRegistrationNameMapper;
    @Autowired
    private JgVehicleInformationMapper vehicleInformationMapper;
    @Autowired
    private JgChangeVehicleRegistrationUnitMapper changeVehicleRegistrationUnitMapper;
    @Autowired
    private IdxBizJgRegisterInfoServiceImpl idxBizJgRegisterInfoService;
    @Autowired
    private EmqKeeper emqKeeper;
    @Autowired
    private JgEquipTransferServiceImpl equipTransferService;
    @Autowired
    JgUseRegistrationManageServiceImpl jgUseRegistrationManageServiceImpl;
    @Autowired
    IdxBizJgProjectContraptionServiceImplService idxBizJgProjectContraptionService;
    @Autowired
    TcmServiceFeignClient tcmServiceFeignClient;
    @Autowired
    private TzBaseEnterpriseInfoMapper tzBaseEnterpriseInfoMapper;
    @Autowired
    private TzsUserInfoMapper tzsUserInfoMapper;
    @Autowired
    private CbDataDictTypeHandler cbDataDictTypeHandler;
    private final String DOWN_LOAD_START_TEMP = "{\"id\":\"%s\",\"status\":\"starting\",\"fileName\":\"%s\",\"time\":\"%s\"}";
    private final String BUCKET_NAME = "upload";
    private final String UPLOAD_PATH = "/tzs/excelTempFile";
    private final int PAGE_SIZE = 1000;
    private final String DOWNLOAD_TOPIC = "/topic/download/excel/%s";
    private final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());


    @Override
    public void gen(String jsonName, String voName, String tableName) {
        String voContent = "package com.yeejoin.amos.boot.module.jg.api.vo.tableDataExportVo;\n" +
                "\n" +
                "import com.alibaba.excel.annotation.ExcelProperty;\n" +
                "import lombok.Data;\n" +
                "\n" +
                "/**\n" +
                " * %s\n" +
                " */\n" +
                "@Data\n" +
                "public class %s {\n";

        String tem = "    \n" +
                "    @ExcelProperty(value = \"%s\", index = %s)\n" +
                "    String %s;\n";
        final String jsonPrefix = "D:\\";
        String jsonPath = jsonPrefix + jsonName + ".json";
        final String voPrefix = "C:\\YeeJoinProjects\\amos-boot-biz\\amos-boot-system-tzs\\amos-boot-module-jg\\amos-boot-module-jg-api\\src\\main\\java\\com\\yeejoin\\amos\\boot\\module\\jg\\api\\vo\\tableDataExportVo";
        try {
            // 读取 JSON 文件内容为字符串
            String jsonContent = new String(Files.readAllBytes(Paths.get(jsonPath)));
            JSONObject js = JSON.parseObject(jsonContent);
            JSONObject uiobject = JSON.parseObject(JSON.toJSONString(js.get("uiobject")));
            JSONArray children = JSON.parseArray(JSON.toJSONString(uiobject.get("children")));
            JSONObject children0 = JSON.parseObject(JSON.toJSONString(children.get(0)));
            JSONObject visualParams = JSON.parseObject(JSON.toJSONString(children0.get("visualParams")));
            JSONArray target = JSON.parseArray(JSON.toJSONString(visualParams.get("columnsSetting")));

            String content = String.format(voContent, tableName, voName.substring(0, 1).toUpperCase() + voName.substring(1) + "Vo");
            for (int i = 0; i < target.size(); i++) {
                JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(target.get(i)));
                String title = String.valueOf(jsonObject.get("title"));
                String dataIndex = String.valueOf(jsonObject.get("dataIndex"));
                content = content + String.format(tem, title, i, dataIndex);
            }

            content = content + "}\n";

            // controller层
            String controller = String.format("@TycloudOperation(ApiLevel = UserType.AGENCY)\n" +
                    "    @GetMapping(value = \"/%s\")\n" +
                    "    @ApiOperation(httpMethod = \"GET\", value = \"%s列表数据导出\", notes = \"%s列表数据导出\")\n" +
                    "    public void " + "%s" + "Export(HttpServletResponse response, String ids) {\n" +
                    "        Assert.hasText(ids,\"未选择导出数据\");\n" +
                    "        iJgTableDataExportService." + "%s" + "(response, Arrays.asList(ids.split(\",\")));\n" +
                    "    }\n", voName, tableName, tableName, voName, voName);
            // interface层
            String interfac = String.format("void %s(HttpServletResponse response, List<String> ids);\n", voName);
            // server层
            String service = String.format("/**\n" +
                    "     * %s列表数据导出\n" +
                    "     *\n" +
                    "     * @param response 响应\n" +
                    "     * @param ids 数据id\n" +
                    "     */\n" +
                    "    @Override\n" +
                    "    public void %s(HttpServletResponse response, List<String> ids) {\n" +
                    "        List<%sVo> exportData = .query%sInIds(ids);\n" +
                    "        ExcelUtil.createTemplate(response, \"%s列表数据\", \"%s列表\", exportData, " + "%sVo" + ".class, null, false);\n" +
                    "    }\n", tableName, voName, voName.substring(0, 1).toUpperCase() + voName.substring(1), voName.substring(0, 1).toUpperCase() + voName.substring(1), tableName, tableName, voName.substring(0, 1).toUpperCase() + voName.substring(1));
            // mapper
            String mapper = String.format("List<%sVo> query%sInIds(@Param(\"ids\") List<String> ids);\n", voName.substring(0, 1).toUpperCase() + voName.substring(1)
                    , voName.substring(0, 1).toUpperCase() + voName.substring(1));
            // mapperxml
            String mapperxml = String.format("<select id=\"query%sInIds\" resultType=\"com.yeejoin.amos.boot.module.jg.api.vo.tableDataExportVo.%sVo\">\n" +
                            "        <include refid=\"page_list\"/>\n" +
                            "        from tzs_jg_use_registration_manage tjurm\n" +
                            "        <where>\n" +
                            "            <if test='ids != null'>\n" +
                            "                and tjurm.sequence_nbr in\n" +
                            "                <foreach collection=\"ids\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n" +
                            "                    #{id}\n" +
                            "                </foreach>\n" +
                            "            </if>\n" +
                            "        </where>\n" +
                            "    </select>\n", voName.substring(0, 1).toUpperCase() + voName.substring(1)
                    , voName.substring(0, 1).toUpperCase() + voName.substring(1));
            content = content + controller + interfac + service + mapper + mapperxml;
            Path filePath = Paths.get(voPrefix, voName.substring(0, 1).toUpperCase() + voName.substring(1) + "Vo" + ".java");
            Files.write(filePath, content.getBytes());
        } catch (IOException e) {
            e.printStackTrace(); // 处理文件读取错误
        }

    }


    /**
     * 开始下载 发送消息
     */
    public void startDownLoadMsg(String fileName, String uuid) {
        try {
            emqKeeper.getMqttClient().publish(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), String.format(DOWN_LOAD_START_TEMP, uuid, fileName, new Date().getTime()).getBytes(StandardCharsets.UTF_8), 2, false);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 发送主题消息，给企业推送excel 结束下载提醒
     *
     * @param topic      主体格式为： /download/excel/${token}
     * @param jsonObject 文件名称 + excel文件路径（minio）
     */
    public void sendDownLoadExcelMsg(String topic, JSONObject jsonObject) {
        try {
            emqKeeper.getMqttClient().publish(topic, JSONObject.toJSONString(jsonObject).getBytes(StandardCharsets.UTF_8), 2, false);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 上传excel文件到minio服务器
     *
     * @param templateExcelFile 文件
     * @return minio文件路径
     */
    private String uploadExcelFile(MultipartFile templateExcelFile) {
        FeignClientResult<Map<String, String>> uploadResult = Systemctl.fileStorageClient.updateBucketFile(templateExcelFile, BUCKET_NAME, UPLOAD_PATH);

        String urlString = "";
        if (uploadResult != null && uploadResult.getResult() != null) {
            for (String s : uploadResult.getResult().keySet()) {
                urlString = s;
            }
        }
        return urlString;
    }

    /**
     * 登记证列表数据导出
     */
    @Override
    public void certificate(String uuid, JgUseRegistrationManageDto dto, Boolean isJG, List<String> ids, String sort) {
        RequestContextWrapper contextWrapper = RequestContextWrapper.capture();

        List<CertificateVo> exportData;
        if (ids.isEmpty()) {
            // 查询首页数据
            int currentPage = 1;
            Page<JgUseRegistrationManageDto> dtoPage = isJG ? jgUseRegistrationManageServiceImpl.queryForJgUseRegistrationManagePageForJG(dto, sort, currentPage, PAGE_SIZE)
                    : jgUseRegistrationManageServiceImpl.queryForJgUseRegistrationManagePage(jgUseRegistrationManageServiceImpl.buildFilter(dto, currentPage, PAGE_SIZE), dto, sort);
            long total = dtoPage.getTotal();
            int totalPage = (int) Math.ceil((double) total / PAGE_SIZE);

            // 用于收集所有分页结果
            List<CompletableFuture<List<String>>> futures = new ArrayList<>();
            // 添加第一页数据
            List<String> idsCollected = dtoPage.getRecords().stream()
                    .map(JgUseRegistrationManageDto::getSequenceNbr)
                    .map(String::valueOf)
                    .collect(Collectors.toList());

            // 多线程处理从第2页开始的数据
            for (int i = 2; i <= totalPage; i++) {
                int pageIndex = i;
                CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
                    // 恢复上下文到子线程
                    contextWrapper.apply();
                    Page<JgUseRegistrationManageDto> resultPage = isJG ? jgUseRegistrationManageServiceImpl.queryForJgUseRegistrationManagePageForJG(dto, sort, pageIndex, PAGE_SIZE)
                            : jgUseRegistrationManageServiceImpl.queryForJgUseRegistrationManagePage(jgUseRegistrationManageServiceImpl.buildFilter(dto, pageIndex, PAGE_SIZE), dto, sort);
                    return resultPage.getRecords().stream()
                            .map(JgUseRegistrationManageDto::getSequenceNbr)
                            .map(String::valueOf)
                            .collect(Collectors.toList());
                }, executorService);
                futures.add(future);
            }

            // 等待所有线程完成
            for (CompletableFuture<List<String>> future : futures) {
                try {
                    idsCollected.addAll(future.get());
                } catch (InterruptedException | ExecutionException e) {
                    log.error("分页查询线程执行失败", e);
                }
            }

            ids.addAll(idsCollected);

        }
        // 查询数据
        List<CertificateVo> equData = useRegistrationManageMapper.queryCertificateInIds(ids);
        // 填充数据
        exportData = this.packageCertificateDetailsField(equData);
        DictUtil.dictCode2DictName(exportData);
        MultipartFile templateExcelFile = ExcelUtil.createTemplateExcelFile("使用登记证列表数据", "使用登记证列表", exportData, CertificateVo.class, null, false);

        String urlString = this.uploadExcelFile(templateExcelFile);

        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "使用登记证列表数据")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
    }

    /**
     * 填充使用登记证详情字段
     * 普通设备填充设备信息，管道填充工程装置
     */
    private List<CertificateVo> packageCertificateDetailsField(List<CertificateVo> equdata) {
        List<CertificateVo> exportData = new ArrayList<>();
        equdata.forEach(data -> {
            if ("压力管道".equals(data.getEquList())) {
                List<IdxBizJgProjectContraption> contraptions = idxBizJgProjectContraptionService.queryProConByCertSeq(data.getSequenceNbr());
                for (IdxBizJgProjectContraption obj : contraptions) {
                    CertificateVo newData = new CertificateVo();
                    BeanUtil.copyProperties(data, newData);
                    BeanUtil.copyProperties(obj, newData);
                    exportData.add(newData);
                }
            } else {
                List<JSONObject> jsonObjects = jgUseRegistrationManageServiceImpl.queryEquByCertificateSeq(Long.valueOf(data.getSequenceNbr()));
                for (JSONObject obj : jsonObjects) {
                    CertificateVo newData = new CertificateVo();
                    BeanUtil.copyProperties(data, newData);
                    BeanUtil.copyProperties(obj, newData);
                    exportData.add(newData);
                }
            }
        });

        return exportData;
    }


    /**
     * 维保备案列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void maintenance(HttpServletResponse response, List<String> ids) {
        List<MaintenanceVo> exportData = maintenanceContractMapper.queryMaintenanceInIds(ids);
        ExcelUtil.createTemplate(response, "维保备案列表数据", "维保备案列表", exportData, MaintenanceVo.class, null, false);
    }

    /**
     * 安装告知列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void installation(HttpServletResponse response, List<String> ids) {
        List<InstallationVo> exportData = installationNoticeService.queryInstallationInIds(ids);
        ExcelUtil.createTemplate(response, "安装告知列表数据", "安装告知列表", exportData, InstallationVo.class, null, false);
    }

    /**
     * 维修告知列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void maintain(HttpServletResponse response, List<String> ids) {
        List<MaintainVo> exportData = maintainNoticeService.queryMaintainInIds(ids);
        ExcelUtil.createTemplate(response, "维修告知列表数据", "维修告知列表", exportData, MaintainVo.class, null, false);
    }

    /**
     * 改造告知列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void reform(HttpServletResponse response, List<String> ids) {
        List<ReformVo> exportData = reformNoticeService.queryReformInIds(ids);
        ExcelUtil.createTemplate(response, "改造告知列表数据", "改造告知列表", exportData, ReformVo.class, null, false);
    }

    /**
     * 移装告知列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void transfer(HttpServletResponse response, List<String> ids) {
        List<TransferVo> exportData = transferNoticeService.queryTransferInIds(ids);
        ExcelUtil.createTemplate(response, "移装告知列表数据", "移装告知列表", exportData, TransferVo.class, null, false);
    }

    /**
     * 使用登记列表数据导出
     *
     * @param response 响应
     * @param dto      筛选面板数据
     */
    @Override
    public void registration(HttpServletResponse response, JgUseRegistrationDto dto, String client) {
        if (dto.getAuditPassDateRange() != null && !dto.getAuditPassDateRange().isEmpty()) {
            String startDate = dto.getAuditPassDateRange().get(0).substring(1);
            String endDate = dto.getAuditPassDateRange().get(1).substring(0, dto.getAuditPassDateRange().get(1).length() - 1);
            if (!ValidationUtil.isEmpty(startDate) && !ValidationUtil.isEmpty(endDate)) {
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                Date start = null;
                Date end = null;
                try {
                    start = dateFormat.parse(startDate);
                    end = dateFormat.parse(endDate);
                } catch (ParseException e) {
                    throw new RuntimeException(e);
                }
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(start);
                calendar.add(Calendar.DAY_OF_MONTH, -1); // 减去一天
                start = calendar.getTime();
                dto.setAuditPassDateStart(start);
                dto.setAuditPassDateEnd(end);
            }
        }
        List<RegistrationVo> exportData = registrationMapper.queryRegistrationInIds(dto, client);
        for (RegistrationVo vo : exportData) {
            vo.setEquCode(limitByComma(vo.getEquCode()));
            vo.setSupervisoryCode(limitByComma(vo.getSupervisoryCode()));
            vo.setRegType(RegTypeEnum.getNameByCode(vo.getRegType()).orElse(RegTypeEnum.REGISTRATION_NEW.getName()));
        }
        ExcelUtil.createTemplate(response, "使用登记列表数据", "使用登记列表", exportData, RegistrationVo.class, null, false);
    }

    /**
     * 截取逗号分隔字符串，只保留前100项，多余用 "..." 代替
     */
    private String limitByComma(String equCode) {
        if (equCode == null || equCode.trim().isEmpty()) {
            return "";
        }
        String[] parts = equCode.split(",");
        if (parts.length <= 100) {
            return equCode;
        }
        // 只保留前100项并添加省略号
        return String.join(",", Arrays.copyOf(parts, 100)) + "...";
    }

    /**
     * 单位变更列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void changeRegistrationUnit(HttpServletResponse response, List<String> ids) {
        List<ChangeRegistrationUnitVo> exportData = changeRegistrationUnitMapper.queryChangeRegistrationUnitInIds(ids);
        ExcelUtil.createTemplate(response, "单位变更列表数据", "单位变更列表", exportData, ChangeRegistrationUnitVo.class, null, false);
    }

    /**
     * 改造登记列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void changeRegistrationReform(HttpServletResponse response, List<String> ids) {
        List<ChangeRegistrationReformVo> exportData = changeRegistrationReformMapper.queryChangeRegistrationReformInIds(ids);
        ExcelUtil.createTemplate(response, "改造登记列表数据", "改造登记列表", exportData, ChangeRegistrationReformVo.class, null, false);
    }


    /**
     * 启用停用列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void enableDisable(HttpServletResponse response, List<String> ids) {
        List<EnableDisableVo> exportData = enableDisableMapper.queryEnableDisableInIds(ids);
        ExcelUtil.createTemplate(response, "启用停用列表数据", "启用停用列表", exportData, EnableDisableVo.class, null, false);
    }


    /**
     * 注销报废列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void scrapCancel(HttpServletResponse response, List<String> ids) {
        List<ScrapCancelVo> exportData = scrapCancelService.queryScrapCancelInIds(ids);
        ExcelUtil.createTemplate(response, "注销报废列表数据", "注销报废列表", exportData, ScrapCancelVo.class, null, false);
    }


    /**
     * 移装变更列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void changeRegistrationTransfer(HttpServletResponse response, List<String> ids) {
        List<ChangeRegistrationTransferVo> exportData = changeRegistrationTransferMapper.queryChangeRegistrationTransferInIds(ids);
        ExcelUtil.createTemplate(response, "移装变更列表数据", "移装变更列表", exportData, ChangeRegistrationTransferVo.class, null, false);
    }


    /**
     * 更名变更列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void changeRegistrationName(HttpServletResponse response, List<String> ids) {
        List<ChangeRegistrationNameVo> exportData = changeRegistrationNameMapper.queryChangeRegistrationNameInIds(ids);
        ExcelUtil.createTemplate(response, "更名变更列表数据", "更名变更列表", exportData, ChangeRegistrationNameVo.class, null, false);
    }


    /**
     * 车气登记列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void vehicleInformation(HttpServletResponse response, List<String> ids) {
        List<VehicleInformationVo> exportData = vehicleInformationMapper.queryVehicleInformationInIds(ids);
        ExcelUtil.createTemplate(response, "车气登记列表数据", "车气登记列表", exportData, VehicleInformationVo.class, null, false);
    }


    /**
     * 车用气瓶变更列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void changeVehicleRegistrationUnit(HttpServletResponse response, List<String> ids) {
        List<ChangeVehicleRegistrationUnitVo> exportData = changeVehicleRegistrationUnitMapper.queryChangeVehicleRegistrationUnitInIds(ids);
        ExcelUtil.createTemplate(response, "车用气瓶变更列表数据", "车用气瓶变更列表", exportData, ChangeVehicleRegistrationUnitVo.class, null, false);
    }


    /**
     * 未纳管设备列表数据导出
     */
    @Override
    public void unregulatedEquip(String uuid, Map<String, Object> map) {
        List<String> ids = getEquRecords(map);
        // 查询数据
        List<JSONObject> jsonObjects = idxBizJgRegisterInfoService.queryEquipInIds(ids);
        List<UnregulatedEquipVo> exportData = JSON.parseArray(JSON.toJSONString(jsonObjects), UnregulatedEquipVo.class);
        DictUtil.dictCode2DictName(exportData);
        MultipartFile templateExcelFile = ExcelUtil.createTemplateExcelFile("未纳管设备列表数据", "未纳管设备列表", exportData, UnregulatedEquipVo.class, null, false);
        String urlString = this.uploadExcelFile(templateExcelFile);

        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "未纳管设备列表数据")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
    }

    private List<String> getEquRecords(Map<String, Object> map) {
        List<String> ids = new ArrayList<>(Optional.ofNullable(map.get("ids"))
                .map(Object::toString)
                .filter(s -> !s.isEmpty())
                .map(s -> Arrays.stream(s.split(","))
                        .collect(Collectors.toList()))
                .orElse(Collections.emptyList()));

        RequestContextWrapper contextWrapper = RequestContextWrapper.capture();

        if (ids.isEmpty()) {
            // 查询首页数据
            Page<JSONObject> jsonObjectPage = idxBizJgRegisterInfoService.queryForEquipmentRegisterPage(new JSONObject(map).fluentPut("size", PAGE_SIZE).fluentPut("number", 1));
            long total = jsonObjectPage.getTotal();
            int totalPage = (int) Math.ceil((double) total / PAGE_SIZE);

            // 用于收集所有分页结果
            List<CompletableFuture<List<String>>> futures = new ArrayList<>();
            // 添加第一页数据
            List<String> idsCollected = jsonObjectPage.getRecords().stream()
                    .map(jsonObject -> jsonObject.getString("record"))
                    .map(String::valueOf)
                    .collect(Collectors.toList());

            // 多线程处理从第2页开始的数据
            for (int i = 2; i <= totalPage; i++) {
                int pageIndex = i;
                CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
                    // 恢复上下文到子线程
                    contextWrapper.apply();
                    Page<JSONObject> resultPage = idxBizJgRegisterInfoService.queryForEquipmentRegisterPage(new JSONObject(map).fluentPut("size", PAGE_SIZE).fluentPut("number", pageIndex));
                    return resultPage.getRecords().stream()
                            .map(jsonObject -> jsonObject.getString("record"))
                            .map(String::valueOf)
                            .collect(Collectors.toList());
                }, executorService);
                futures.add(future);
            }

            // 等待所有线程完成
            for (CompletableFuture<List<String>> future : futures) {
                try {
                    idsCollected.addAll(future.get());
                } catch (InterruptedException | ExecutionException e) {
                    log.error("分页查询线程执行失败", e);
                }
            }

            ids.addAll(idsCollected);

        }
        return ids;
    }


    /**
     * 已纳管设备列表数据导出
     */
    @Override
    public void manageEquipment(String uuid, Map<String, Object> map) {
        List<String> ids = getEquRecords(map);
        // 查询数据
        List<JSONObject> jsonObjects = idxBizJgRegisterInfoService.queryEquipInIds(ids);
        List<ManageEquipmentVo> exportData = JSON.parseArray(JSON.toJSONString(jsonObjects), ManageEquipmentVo.class);
        DictUtil.dictCode2DictName(exportData);
        MultipartFile templateExcelFile = ExcelUtil.createTemplateExcelFile("已纳管设备列表数据", "已纳管设备列表", exportData, ManageEquipmentVo.class, null, false);
        String urlString = this.uploadExcelFile(templateExcelFile);

        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "已纳管设备列表数据")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));

    }


    /**
     * 设备移交列表数据导出
     *
     * @param response 响应
     * @param ids      数据id
     */
    @Override
    public void equipTransfer(HttpServletResponse response, List<String> ids) {
        List<EquipTransferVo> exportData = equipTransferService.queryTransferInIds(ids);
        ExcelUtil.createTemplate(response, "设备移交列表数据", "设备移交列表", exportData, EquipTransferVo.class, null, false);
    }

    private List<String> getProConSeqs(Map<String, String> params, String sort, ReginParams reginParams) {
        List<String> ids = new ArrayList<>(Optional.ofNullable(params.get("ids"))
                .map(Object::toString)
                .filter(s -> !s.isEmpty())
                .map(s -> Arrays.stream(s.split(","))
                        .collect(Collectors.toList()))
                .orElse(Collections.emptyList()));

        RequestContextWrapper contextWrapper = RequestContextWrapper.capture();

        if (ids.isEmpty()) {
            // 查询首页数据
            IPage<IdxBizJgProjectContraption> projectContraptionIPage = idxBizJgProjectContraptionService.proConPageByParams(1, PAGE_SIZE, sort, params, reginParams);
            long total = projectContraptionIPage.getTotal();
            int totalPage = (int) Math.ceil((double) total / PAGE_SIZE);

            // 用于收集所有分页结果
            List<CompletableFuture<List<String>>> futures = new ArrayList<>();
            // 添加第一页数据
            List<String> idsCollected = projectContraptionIPage.getRecords().stream()
                    .map(BaseEntity::getSequenceNbr)
                    .map(String::valueOf)
                    .collect(Collectors.toList());

            // 多线程处理从第2页开始的数据
            for (int i = 2; i <= totalPage; i++) {
                int pageIndex = i;
                CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
                    // 恢复上下文到子线程
                    contextWrapper.apply();
                    IPage<IdxBizJgProjectContraption> resultPage = idxBizJgProjectContraptionService.proConPageByParams(pageIndex, PAGE_SIZE, sort, params, reginParams);
                    return resultPage.getRecords().stream()
                            .map(BaseEntity::getSequenceNbr)
                            .map(String::valueOf)
                            .collect(Collectors.toList());
                }, executorService);
                futures.add(future);
            }

            // 等待所有线程完成
            for (CompletableFuture<List<String>> future : futures) {
                try {
                    idsCollected.addAll(future.get());
                } catch (InterruptedException | ExecutionException e) {
                    log.error("分页查询线程执行失败", e);
                }
            }
            ids.addAll(idsCollected);
        }
        return ids;
    }

    /**
     * 已纳管压力管道列表数据导出
     *
     * @param params
     * @param sort
     * @param reginParams
     */
    @Override
    public void managePipe(String uuid, Map<String, String> params, String sort, ReginParams reginParams) {
        List<String> proConSeqs = getProConSeqs(params, sort, reginParams);
        List<JSONObject> jsonObjects = idxBizJgRegisterInfoService.queryPipeEquipInIds(proConSeqs);
        List<PipeEquipmentVo> exportData = JSON.parseArray(JSON.toJSONString(jsonObjects), PipeEquipmentVo.class);
        DictUtil.dictCode2DictName(exportData);
        MultipartFile templateExcelFile = ExcelUtil.createTemplateExcelFile("已纳管压力管道列表数据", "已纳管压力管道列表", exportData, PipeEquipmentVo.class, null, false);
        String urlString = this.uploadExcelFile(templateExcelFile);

        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "已纳管压力管道列表")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
    }

    /**
     * 未纳管压力管道列表数据导出
     *
     * @param params
     * @param sort
     * @param reginParams
     */
    @Override
    public void unregulatedPipe(String uuid, Map<String, String> params, String sort, ReginParams reginParams) {
        List<String> proConSeqs = getProConSeqs(params, sort, reginParams);
        List<JSONObject> jsonObjects = idxBizJgRegisterInfoService.queryPipeEquipInIds(proConSeqs);
        List<PipeEquipmentVo> exportData = JSON.parseArray(JSON.toJSONString(jsonObjects), PipeEquipmentVo.class);
        DictUtil.dictCode2DictName(exportData);
        MultipartFile templateExcelFile = ExcelUtil.createTemplateExcelFile("未纳管压力管道列表数据", "未纳管压力管道列表", exportData, PipeEquipmentVo.class, null, false);
        String urlString = this.uploadExcelFile(templateExcelFile);
        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "未纳管压力管道列表")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
    }

    private List<Map<String, String>> getEnterList(String ids, Map<String, Object> map) {
        RequestContextWrapper contextWrapper = RequestContextWrapper.capture();
        List<Map<String, String>> resultList = new ArrayList<>();
        if (StringUtils.isEmpty(ids)) {
            // 查询第一页
            ResponseModel<Page<Map<String, String>>> page =
                    tcmServiceFeignClient.page(1, PAGE_SIZE, null, map);
            Page<Map<String, String>> pageResult = page.getResult();
            int totalPage = (int) Math.ceil((double) pageResult.getTotal() / PAGE_SIZE);
            resultList.addAll(pageResult.getRecords());
            List<CompletableFuture<List<Map<String, String>>>> futures = new ArrayList<>();
            for (int i = 2; i <= totalPage; i++) {
                int pageIndex = i;
                CompletableFuture<List<Map<String, String>>> future =
                        CompletableFuture.supplyAsync(() -> {
                            contextWrapper.apply();
                            ResponseModel<Page<Map<String, String>>> pageData =
                                    tcmServiceFeignClient.page(pageIndex, PAGE_SIZE, null, map);
                            return pageData.getResult().getRecords();
                        }, executorService);
                futures.add(future);
            }

            // 等待所有线程完成
            for (CompletableFuture<List<Map<String, String>>> future : futures) {
                try {
                    resultList.addAll(future.get());
                } catch (InterruptedException | ExecutionException e) {
                    log.error("分页查询线程执行失败", e);
                }
            }
        } else {
            List<Long> idList = Arrays.stream(ids.split(","))
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .map(Long::valueOf)
                    .collect(Collectors.toList());
            if (!idList.isEmpty()) {
                ResponseModel<List<Map<String, String>>> responseModel = tcmServiceFeignClient.getListByIds(idList);
                if (responseModel != null && responseModel.getResult() != null) {
                    resultList.addAll(responseModel.getResult());
                }
            }
        }
        return resultList;
    }

    public static <T, R> List<R> batchQuery(List<T> list, int batchSize, Function<List<T>, List<R>> function) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<R> result = new ArrayList<>();
        for (int i = 0; i < list.size(); i += batchSize) {
            int end = Math.min(i + batchSize, list.size());
            List<T> subList = list.subList(i, end);
            List<R> batch = function.apply(subList);
            if (CollectionUtils.isNotEmpty(batch)) {
                result.addAll(batch);
            }
        }
        return result;
    }

    /**
     * 基础设置-企业信息列表数据导出
     *
     * @param ids
     */
    @Override
    public void enterpriseInformationExport(String uuid, String ids, Map<String, Object> map) {
        ObjectMapper objectMapper = new ObjectMapper();
        List<Map<String, String>> enterSeqs = getEnterList(ids, map);
        List<Map<String, String>> source = enterSeqs;
        boolean hasUseUnit = Optional.ofNullable(map.get("unitTypeList"))
                .map(Object::toString)
                .filter(ObjectUtils::isNotEmpty)
                .map(s -> Arrays.stream(s.split(","))
                        .map(String::trim)
                        .anyMatch(t -> t.contains("使用单位") || t.contains("个人主体")))
                .orElse(false);
        if (!hasUseUnit) {
            source = batchQuery(
                    enterSeqs,
                    500,
                    batch -> {
                        List<String> sequenceNbrs = batch.stream()
                                .map(m -> m.get("sequenceNbr"))
                                .filter(ObjectUtils::isNotEmpty)
                                .collect(Collectors.toList());
                        return tzBaseEnterpriseInfoMapper.getEnterInfoWithExport(sequenceNbrs);
                    }
            );
        }
        List<BaseEnterpriseVo> exportData = JSON.parseArray(JSON.toJSONString(source), BaseEnterpriseVo.class);
        exportData.forEach(item -> {
            String categoryJson = item.getEquipCategory();
            if (categoryJson != null && !categoryJson.isEmpty()) {
                try {
                    List<String> codes = objectMapper.readValue(categoryJson, new TypeReference<List<String>>() {
                    });
                    List<String> names = codes.stream()
                            .map(x -> cbDataDictTypeHandler.handle("BJSBZL", x))
                            .filter(Objects::nonNull)
                            .collect(Collectors.toList());
                    item.setEquipCategory(String.join("、", names));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        DictUtil.dictCode2DictName(exportData);
        MultipartFile templateExcelFile = ExcelUtil.createTemplateExcelFile("企业信息列表数据", "企业信息列表列表", exportData, BaseEnterpriseVo.class, null, false);
        String urlString = this.uploadExcelFile(templateExcelFile);
        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "企业信息列表")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
    }

    private List<String> getUserInfoSeqs(boolean isAdmin, String ids, Map<String, Object> map) {
        RequestContextWrapper contextWrapper = RequestContextWrapper.capture();
        List<String> idsList = new ArrayList<>();
        if (StringUtils.isEmpty(ids)) {
            ResponseModel<Page<Map<String, String>>> page = isAdmin ? tcmServiceFeignClient.getUserByPermission(1, PAGE_SIZE, null, "all", map) :
                    tcmServiceFeignClient.page("1", String.valueOf(PAGE_SIZE), null, map);
            Page<Map<String, String>> pageResult = page.getResult();
            int totalPage = (int) Math.ceil((double) pageResult.getTotal() / PAGE_SIZE);
            List<CompletableFuture<List<String>>> futures = new ArrayList<>();
            List<String> idsCollected = pageResult.getRecords().stream()
                    .map(item -> item.getOrDefault("sequenceNbr", null))
                    .filter(Objects::nonNull)
                    .map(String::valueOf)
                    .collect(Collectors.toList());

            for (int i = 2; i <= totalPage; i++) {
                int pageIndex = i;
                CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
                    contextWrapper.apply();
                    ResponseModel<Page<Map<String, String>>> page1 = isAdmin ? tcmServiceFeignClient.getUserByPermission(pageIndex, PAGE_SIZE, null, "all", map) :
                            tcmServiceFeignClient.page(String.valueOf(pageIndex), String.valueOf(PAGE_SIZE), null, map);
                    Page<Map<String, String>> resultPage = page1.getResult();
                    return resultPage.getRecords().stream()
                            .map(item -> item.getOrDefault("sequenceNbr", null))
                            .filter(Objects::nonNull)
                            .map(String::valueOf)
                            .collect(Collectors.toList());
                }, executorService);
                futures.add(future);
            }
            for (CompletableFuture<List<String>> future : futures) {
                try {
                    idsCollected.addAll(future.get());
                } catch (InterruptedException | ExecutionException e) {
                    log.error("人员列表分页查询线程执行失败", e);
                }
            }
            idsList.addAll(idsCollected);
        } else {
            idsList.addAll(Arrays.asList(ids.split(",")));
        }
        return idsList;
    }


    @Override
    public void userInfoExport(String uuid, String ids, Map<String, Object> map) {
        List<String> userInfoSeqs = getUserInfoSeqs(false, ids, map);
        List<Map<String, String>> enterInfoWithExport = tzsUserInfoMapper.getUserInfoWithExport("false",userInfoSeqs);
        List<UserInfoVo> exportData = JSON.parseArray(JSON.toJSONString(enterInfoWithExport), UserInfoVo.class);
        DictUtil.dictCode2DictName(exportData);
        MultipartFile templateExcelFile = ExcelUtil.createTemplateExcelFile("人员信息列表数据", "人员信息列表列表", exportData, UserInfoVo.class, null, false);
        String urlString = this.uploadExcelFile(templateExcelFile);
        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "人员信息列表")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
    }

    @Override
    public void userInfoExportWithAdmin(String uuid, String ids, Map<String, Object> map) {
        List<String> userInfoSeqs = getUserInfoSeqs(true, ids, map);
        List<Map<String, String>> enterInfoWithExport = tzsUserInfoMapper.getUserInfoWithExport("true", userInfoSeqs);
        List<UserInfoVo> exportData = JSON.parseArray(JSON.toJSONString(enterInfoWithExport), UserInfoVo.class);
        DictUtil.dictCode2DictName(exportData);
        MultipartFile templateExcelFile = ExcelUtil.createTemplateExcelFile("人员信息列表数据", "人员信息列表列表", exportData, UserInfoVo.class, null, false);
        String urlString = this.uploadExcelFile(templateExcelFile);
        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "人员信息列表")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
    }

    @Override
    public void exportXianElevatorData(HttpServletResponse response, String beginDate, String endDate) {
        List<XianElevatorVo> exportData = registrationMapper.queryXianElevatorData(beginDate, endDate);
        for (XianElevatorVo vo : exportData) {
            vo.setRegOrgId(RegOrgEnum.getCodeByName(vo.getRegOrgId()).orElse(""));
            boolean isXaHistory = Optional.ofNullable(vo.getDataSource())
                    .map(ds -> ds.contains("jg_his_xa"))
                    .orElse(false);
            vo.setRegCode(isXaHistory ? vo.getRegCode() : "");
            vo.setUseInnerCode(Optional.ofNullable(vo.getUseInnerCode())
                    .filter(v -> !"null".equalsIgnoreCase(v.trim()))
                    .orElse(""));
        }
        ExcelUtil.createTemplate(response, "西安电梯设备数据导出", "西安电梯设备数据导出", exportData, XianElevatorVo.class, null, false);
    }
}