package com.yeejoin.amos.boot.module.jg.biz.data.fix.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yeejoin.amos.boot.module.common.api.dao.ESEquipmentCategory;
import com.yeejoin.amos.boot.module.common.api.dto.ESEquipmentCategoryDto;
import com.yeejoin.amos.boot.module.common.api.entity.ESEquipmentInfo;
import com.yeejoin.amos.boot.module.common.api.entity.EsEntity;
import com.yeejoin.amos.boot.module.jg.biz.data.fix.patcher.FilterableBatchDataPatcher;
import com.yeejoin.amos.boot.module.jg.biz.edit.utils.JsonDiffUtil;
import com.yeejoin.amos.boot.module.jg.biz.refresh.StatisticsDataUpdateService;
import com.yeejoin.amos.boot.module.jg.biz.refresh.handler.EquipmentRefreshHandler;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.EsBulkService;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgInspectionDetectionInfo;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgMaintenanceRecordInfo;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgSupervisionInfo;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgInspectionDetectionInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgMaintenanceRecordInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgSupervisionInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgUseInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StopWatch;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.yeejoin.amos.boot.module.jg.biz.service.impl.DataHandlerServiceImpl.IDX_BIZ_EQUIPMENT_INFO;
import static com.yeejoin.amos.boot.module.jg.biz.service.impl.DataHandlerServiceImpl.IDX_BIZ_VIEW_JG_ALL;

@Component
@Slf4j
public class FilterableEquipInsert2EsPatcher extends FilterableBatchDataPatcher {


    private final ESEquipmentCategory equipmentCategory;

    private final EquipmentRefreshHandler refreshHandler;

    private final IdxBizJgUseInfoMapper idxBizJgUseInfoMapper;

    private final IdxBizJgSupervisionInfoMapper idxBizJgSupervisionInfoMapper;

    private final IdxBizJgMaintenanceRecordInfoMapper maintenanceRecordInfoMapper;

    private final IdxBizJgInspectionDetectionInfoMapper inspectionDetectionInfoMapper;


    private final EsBulkService esBulkService;


    protected FilterableEquipInsert2EsPatcher(ApplicationContext applicationContext, ESEquipmentCategory equipmentCategory, EquipmentRefreshHandler refreshHandler, IdxBizJgUseInfoMapper idxBizJgUseInfoMapper, IdxBizJgSupervisionInfoMapper idxBizJgSupervisionInfoMapper, IdxBizJgMaintenanceRecordInfoMapper maintenanceRecordInfoMapper, IdxBizJgInspectionDetectionInfoMapper inspectionDetectionInfoMapper, EsBulkService esBulkService) {
        super(applicationContext);
        this.equipmentCategory = equipmentCategory;
        this.refreshHandler = refreshHandler;
        this.idxBizJgUseInfoMapper = idxBizJgUseInfoMapper;
        this.idxBizJgSupervisionInfoMapper = idxBizJgSupervisionInfoMapper;
        this.maintenanceRecordInfoMapper = maintenanceRecordInfoMapper;
        this.inspectionDetectionInfoMapper = inspectionDetectionInfoMapper;
        this.esBulkService = esBulkService;
    }

    @Override
    protected void patchBatchRecord(List<String> refreshRecords) {
        log.info("批量处理设备信息到es开始");
        StopWatch watch = new StopWatch();
        watch.start("批量查询设备信息");
        List<Map<String, Object>> details = idxBizJgUseInfoMapper.queryDetailBatch(refreshRecords);
        watch.stop();
        Map<String, Map<String, Object>> recordDetailMap = details.stream().collect(Collectors.toMap(e -> (String) e.get("SEQUENCE_NBR"), Function.identity(), (k1, k2) -> k2));
        watch.start("组装es设备老索引更新及新增的对象数据");
        // 组装es设备老索引更新及新增的对象数据
        List<ESEquipmentCategoryDto> esEquipmentCategoryDtos = getEsEquipmentCategoryDtos(refreshRecords, recordDetailMap);
        watch.stop();
        watch.start("组装es设备新索引更新及新增的对象数据");
        // 组装es设备新索引更新及新增的对象数据
        List<ESEquipmentInfo> esEquipmentInfos = getEsEquipmentInfos(refreshRecords, recordDetailMap);
        watch.stop();
        watch.start("es设备新旧索引保存");
        // 多线程保存
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        if (!esEquipmentCategoryDtos.isEmpty()) {
            futures.add(CompletableFuture.runAsync(() -> {
                StopWatch watch4 = new StopWatch();
                watch4.start();
                esBulkService.bulkUpsert(IDX_BIZ_VIEW_JG_ALL, esEquipmentCategoryDtos.stream().map(e -> new EsEntity<>(e.getSEQUENCE_NBR(), e)).collect(Collectors.toList()));
                watch4.stop();
                log.warn("[设备老索引] 批量入库 {} 条，耗时 {}s",
                        esEquipmentCategoryDtos.size(), watch4.getTotalTimeSeconds());
            }));
        }
        if (!esEquipmentInfos.isEmpty()) {
            futures.add(CompletableFuture.runAsync(() -> {
                StopWatch watch4 = new StopWatch();
                watch4.start();
                esBulkService.bulkUpsert(IDX_BIZ_EQUIPMENT_INFO, esEquipmentInfos.stream().map(e -> new EsEntity<>(e.getSEQUENCE_NBR(), e)).collect(Collectors.toList()));
                watch4.stop();
                log.warn("[设备新索引] 批量入库 {} 条，耗时 {}s",
                        esEquipmentInfos.size(), watch4.getTotalTimeSeconds());
            }));
        }
        // 等待所有任务完成（阻塞当前线程）
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        watch.stop();
        log.warn("新索引数据补充匹配补充，总耗时情况：{}", watch.prettyPrint());
    }

    private List<ESEquipmentInfo> getEsEquipmentInfos(List<String> refreshRecords, Map<String, Map<String, Object>> recordDetailMap) {
        // 设备最新的维保信息-维度：设备
        List<IdxBizJgMaintenanceRecordInfo> lastMaintenanceRecordInfos = maintenanceRecordInfoMapper.selectLastedMainInfoBatch(refreshRecords);
        Map<String, List<IdxBizJgMaintenanceRecordInfo>> recordLastMaintMap = lastMaintenanceRecordInfos.stream().collect(Collectors.groupingBy(IdxBizJgMaintenanceRecordInfo::getRecord));

        // 设备、各检验类型下最新的检验信息-维度：设备、检验类型
        List<IdxBizJgInspectionDetectionInfo> lastedInspectInfosGroupByInspectType = inspectionDetectionInfoMapper.selectLastedGroupByInspectTypeBatch(refreshRecords);
        Map<String, List<IdxBizJgInspectionDetectionInfo>> recordInspectInfosGroupByInspectTypeMap = lastedInspectInfosGroupByInspectType.stream().collect(Collectors.groupingBy(IdxBizJgInspectionDetectionInfo::getRecord));

        // 设备最新的检验信息-维度：设备
        Map<String, Optional<IdxBizJgInspectionDetectionInfo>> recordLastInspectionMap = lastedInspectInfosGroupByInspectType.stream().filter(e -> e.getNextInspectDate() != null).collect(Collectors.groupingBy(IdxBizJgInspectionDetectionInfo::getRecord, Collectors.maxBy(Comparator.comparing(IdxBizJgInspectionDetectionInfo::getNextInspectDate))));
        List<ESEquipmentInfo> esEquipmentInfos = refreshRecords.parallelStream().map(record -> {
            ESEquipmentInfo esEquipmentInfo = null;
            try {
                esEquipmentInfo = new ESEquipmentInfo();
                Map<String, Object> detail = recordDetailMap.get(record);
                StatisticsDataUpdateService.formatUseDate(detail);
                BeanUtil.copyProperties(detail, esEquipmentInfo, true);
                // 最新检验信息-维度record
                IdxBizJgInspectionDetectionInfo inspectionDetectionInfo = Optional.ofNullable(recordLastInspectionMap.get(record)).flatMap(i -> i).orElse(new IdxBizJgInspectionDetectionInfo());
                // 最新维保信息-维度record
                IdxBizJgMaintenanceRecordInfo lastMaintenanceRecordInfo = Optional.ofNullable(recordLastMaintMap.get(record)).filter(l -> !l.isEmpty()).map(list -> list.get(0)).orElse(new IdxBizJgMaintenanceRecordInfo());
                // 最新检验信息-维度record、检验类型，存最新的一条
                List<IdxBizJgInspectionDetectionInfo> inspectionDetectionInfos = recordInspectInfosGroupByInspectTypeMap.getOrDefault(record, new ArrayList<>());
                StatisticsDataUpdateService.formatInspectDate(esEquipmentInfo, inspectionDetectionInfo, record);
                esEquipmentInfo.setIssueDate(refreshHandler.getIssueDate(esEquipmentInfo.getUSE_ORG_CODE()));
                esEquipmentInfo.setMAINTAIN_UNIT(lastMaintenanceRecordInfo.getMeUnitCreditCode());
                esEquipmentInfo.setMAINTAIN_UNIT_NAME(lastMaintenanceRecordInfo.getMeUnitName());
                esEquipmentInfo.setInspections(BeanUtil.copyToList(inspectionDetectionInfos, ESEquipmentInfo.Inspection.class));
                esEquipmentInfo.setMaintenances(lastMaintenanceRecordInfo.getSequenceNbr() != null ? Collections.singletonList(BeanUtil.copyProperties(lastMaintenanceRecordInfo, ESEquipmentInfo.Maintenance.class)) : new ArrayList<>());
                esEquipmentInfo.setTechParams(refreshHandler.buildTechParamByEquList(record, esEquipmentInfo.getEQU_LIST_CODE()));
                if ("8000".equals(esEquipmentInfo.getEQU_LIST_CODE())) {
                    List<ESEquipmentInfo.TechParam> techParams = esEquipmentInfo.getTechParams();
                    List<ESEquipmentInfo.TechParam> pipeLength = techParams.stream().filter(e -> e.getParamKey().equals("pipeLength") && e.getDoubleValue() != null).collect(Collectors.toList());
                    if (!ObjectUtils.isEmpty(pipeLength)) {
                        esEquipmentInfo.setPipeLength(pipeLength.get(0).getDoubleValue());
                    }
                }
            } catch (Exception e) {
                // 异常数据跳过
                log.error("准备新设备索引数据失败：{}", record, e);
            }
            return esEquipmentInfo;
        }).collect(Collectors.toList());
        esEquipmentInfos.remove(null);
        esEquipmentInfos = esEquipmentInfos.stream().filter(e -> StringUtils.isNotEmpty(e.getSEQUENCE_NBR())).collect(Collectors.toList());
        return esEquipmentInfos;
    }

    private List<ESEquipmentCategoryDto> getEsEquipmentCategoryDtos(List<String> refreshRecords, Map<String, Map<String, Object>> recordDetailMap) {
        List<ESEquipmentCategoryDto> esEquipmentCategoryDtos = refreshRecords.parallelStream().map(record -> {
            ESEquipmentCategoryDto esEquipmentInfo = null;
            Optional<ESEquipmentCategoryDto> op = equipmentCategory.findById(record);
            try {
                if (op.isPresent()) {  // 存在更新
                    IdxBizJgSupervisionInfo supervisionInfo = idxBizJgSupervisionInfoMapper.selectOne(new LambdaQueryWrapper<IdxBizJgSupervisionInfo>().eq(IdxBizJgSupervisionInfo::getRecord, record)
                            .select(IdxBizJgSupervisionInfo::getRecord, IdxBizJgSupervisionInfo::getOrgBranchCode, IdxBizJgSupervisionInfo::getOrgBranchName));
                    esEquipmentInfo = op.get();
                    if (supervisionInfo != null && StringUtils.isNotEmpty(supervisionInfo.getOrgBranchCode()) && JsonDiffUtil.isNullOrEmpty(esEquipmentInfo.getOrgBranchCode())) {
                        esEquipmentInfo.setOrgBranchCode(supervisionInfo.getOrgBranchCode());
                        esEquipmentInfo.setORG_BRANCH_NAME(supervisionInfo.getOrgBranchName());
                    }
                } else { // 不存在创建
                    Map<String, Object> detail = recordDetailMap.get(record);
                    esEquipmentInfo = new ESEquipmentCategoryDto();
                    StatisticsDataUpdateService.formatUseDate(detail);
                    BeanUtil.copyProperties(detail, esEquipmentInfo, true);
                }
            } catch (Exception e) {
                log.error("准备老设备索引数据失败：{}", record, e);
            }
            return esEquipmentInfo;
        }).collect(Collectors.toList());
        esEquipmentCategoryDtos.remove(null);
        return esEquipmentCategoryDtos;
    }

    @Override
    protected Map<String, Object> buildFilter(Map<String, Object> params) {
        return params;
    }

    @Override
    protected void beforePatching(String record) {

    }

    @Override
    protected void patchSingleRecord(String record) {
    }


    @Override
    protected void afterPatching(String record) {

    }
}
