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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.yeejoin.amos.boot.biz.common.entity.TzsBaseEntity;
import com.yeejoin.amos.boot.module.common.api.constant.TZSCommonConstant;
import com.yeejoin.amos.boot.module.common.biz.constats.Constants;
import com.yeejoin.amos.boot.module.common.biz.refresh.DataRefreshEvent;
import com.yeejoin.amos.boot.module.jg.api.dto.ReminderItemDto;
import com.yeejoin.amos.boot.module.jg.api.enums.BusinessTypeEnum;
import com.yeejoin.amos.boot.module.jg.biz.event.publisher.EventPublisher;
import com.yeejoin.amos.boot.module.jg.biz.reminder.biz.factory.GradeStrategyFactory;
import com.yeejoin.amos.boot.module.jg.biz.reminder.core.event.EquipCreateOrEditEvent;
import com.yeejoin.amos.boot.module.jg.biz.reminder.core.event.service.DefaultQualityScoreUpdateService;
import com.yeejoin.amos.boot.module.jg.biz.reminder.dto.MatchItemDto;
import com.yeejoin.amos.boot.module.jg.biz.reminder.service.CommonReminderService;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.EsBulkService;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.IdxBizJgRegisterInfoServiceImpl;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.IdxBizJgUseInfoServiceImpl;
import com.yeejoin.amos.boot.module.ymt.api.dto.EquipWaitRefreshDataQualityScore;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgRegisterInfo;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgUseInfo;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
@Slf4j
public class EquipQualityScoreUpdateService extends DefaultQualityScoreUpdateService {

    private final IdxBizJgUseInfoServiceImpl idxBizJgUseInfoService;

    private final IdxBizJgRegisterInfoServiceImpl idxBizJgRegisterInfoService;

    private final CommonReminderService commonReminderService;

    @Value("${grade.calculation.strategy:MAX_GRADE}")
    private String activeStrategy;

    private final GradeStrategyFactory gradeStrategyFactory;

    private final EsBulkService esBulkService;

    private final EventPublisher eventPublisher;

    @Override
    public Boolean support(EquipCreateOrEditEvent.EquipType equipType) {
        return EquipCreateOrEditEvent.EquipType.equip.equals(equipType);
    }


    private Integer getReminderLevel(String bizType, String record) {
        MatchItemDto matchItemDto = MatchItemDto.builder().build();
        IdxBizJgUseInfo useInfo = getIdxBizJgUseInfo(record);
        IdxBizJgRegisterInfo registerInfo = getIdxBizJgRegisterInfo(record);
        if (ValidationUtil.isEmpty(useInfo) || ValidationUtil.isEmpty(registerInfo)) {
            return 0;
        }
        matchItemDto.setBizType(bizType);
        matchItemDto.setEquList(registerInfo.getEquList());
        matchItemDto.setEquCategory(registerInfo.getEquCategory());
        matchItemDto.setEquDefine(registerInfo.getEquDefine());
        matchItemDto.setRegType(CommonReminderService.getRegTypeByDataSource(useInfo.getDataSource()));
        matchItemDto.setIsRegister(useInfo.getIsIntoManagement() && StringUtils.isNotEmpty(registerInfo.getUseOrgCode()));
        matchItemDto.setWhetherVehicleCylinder(StringUtils.isNotEmpty(registerInfo.getWhetherVehicleCylinder()) ? registerInfo.getWhetherVehicleCylinder() : "0");
        ReminderItemDto reminderItemDto = new ReminderItemDto();
        reminderItemDto.setEquipId(record);
        reminderItemDto.setEquipNo(registerInfo.getEquCode());
        reminderItemDto.setEquipName(registerInfo.getProductName());
        reminderItemDto.setDetailData(commonReminderService.getEquipDetailByRecord(record));
        return gradeStrategyFactory.getStrategy(activeStrategy).calculateGrade(Collections.singletonList(reminderItemDto), matchItemDto);
    }

    private IdxBizJgUseInfo getIdxBizJgUseInfo(String record) {
        return idxBizJgUseInfoService.getOne(new LambdaQueryWrapper<IdxBizJgUseInfo>().eq(IdxBizJgUseInfo::getRecord, record)
                .select(IdxBizJgUseInfo::getRecord, IdxBizJgUseInfo::getIsIntoManagement, IdxBizJgUseInfo::getDataSource));
    }

    private IdxBizJgRegisterInfo getIdxBizJgRegisterInfo(String record) {
        return idxBizJgRegisterInfoService.getOne(new LambdaQueryWrapper<IdxBizJgRegisterInfo>()
                .eq(IdxBizJgRegisterInfo::getRecord, record)
                .select(TzsBaseEntity::getSequenceNbr,
                        IdxBizJgRegisterInfo::getRecord,
                        IdxBizJgRegisterInfo::getEquCategory,
                        IdxBizJgRegisterInfo::getEquDefine,
                        IdxBizJgRegisterInfo::getEquList,
                        IdxBizJgRegisterInfo::getWhetherVehicleCylinder,
                        IdxBizJgRegisterInfo::getProductName));
    }

    private void sendDataRefreshMsgEquip(List<String> records) {
        if (ValidationUtil.isEmpty(records)) {
            return;
        }
        eventPublisher.publish(new DataRefreshEvent(this, records, DataRefreshEvent.DataType.equipment.name(), DataRefreshEvent.Operation.UPDATE));
    }

    @Override
    protected Boolean shouldProcess(String bizType) {
        return BusinessTypeEnum.JG_USAGE_REGISTRATION.name().equals(bizType) ||
                BusinessTypeEnum.JG_INSTALLATION_NOTIFICATION.name().equals(bizType) ||
                BusinessTypeEnum.JG_NEW_EQUIP.name().equals(bizType) ||
                BusinessTypeEnum.JG_VEHICLE_GAS_APPLICATION.name().equals(bizType) ||
                Constants.JG_EDIT_EQUIP.equals(bizType);
    }

    @Override
    protected void doHandle(String bizType, Set<String> recordOrPIds) {
        if (recordOrPIds.isEmpty()) {
            return;
        }
        StopWatch watch = new StopWatch();
        watch.start();
        List<IdxBizJgRegisterInfo> idxBizJgRegisterInfos = idxBizJgRegisterInfoService.list(new LambdaQueryWrapper<IdxBizJgRegisterInfo>().in(IdxBizJgRegisterInfo::getRecord, recordOrPIds).select(IdxBizJgRegisterInfo::getRecord, IdxBizJgRegisterInfo::getEquList));
        List<EquipWaitRefreshDataQualityScore> dataQualityScores = idxBizJgRegisterInfos.parallelStream().filter(r -> !EquipmentClassifityEnum.YLGD.getCode().equals(r.getEquList())).map(registerInfo -> {
            EquipWaitRefreshDataQualityScore dataQualityScore = new EquipWaitRefreshDataQualityScore();
            dataQualityScore.setRecord(registerInfo.getRecord());
            try {
                Integer level = this.getReminderLevel(bizType, registerInfo.getRecord());
                dataQualityScore.setDataQualityScore(level);
            } catch (Exception e) {
                log.error("设备：「{}」,计算数据质量登记失败。", registerInfo.getRecord(), e);
                dataQualityScore.setDataQualityScore(null);
            }
            return dataQualityScore;
        }).collect(Collectors.toList());
        if (!dataQualityScores.isEmpty()) {
            // 分批数据库更新
            Lists.partition(dataQualityScores, 200).forEach(partitionData -> {
                try {
                    idxBizJgUseInfoService.getBaseMapper().updateDataQualityScoreBatch(partitionData, null);
                    // es更新
                    esBulkService.bulkUpdateFieldsByIds(this.buildUpdateFields(partitionData), TZSCommonConstant.ES_INDEX_NAME_JG_ALL);
                } catch (Exception e) {
                    log.error("更新数据质量等级失败，数据为：「{}」", partitionData, e);
                }
            });
        }
        watch.stop();
        log.info("计算数据质量等级数量：「{}」，耗时：「{}」", dataQualityScores.size(), watch.getTotalTimeSeconds());
    }


    @Override
    protected void afterHandle(Set<String> recordOrPIds) {
        // 事务提交后发送数据变更消息
        this.sendDataRefreshMsgEquip(new ArrayList<>(recordOrPIds));
    }

}
