package com.hdkj.lt.mq.service.fault.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.common.collect.Lists;
import com.hdkj.lt.base.constants.DictConstants;
import com.hdkj.lt.base.constants.ErrorLogConstant;
import com.hdkj.lt.base.constants.RedisKeyConstants;
import com.hdkj.lt.base.constants.RocketMQConstants;
import com.hdkj.lt.base.enums.EventTypeEnum;
import com.hdkj.lt.base.enums.OperationStepEnum;
import com.hdkj.lt.base.exception.BusinessException;
import com.hdkj.lt.core.bizms.modle.po.FeederTopo;
import com.hdkj.lt.core.bizms.modle.po.GridPdOutageEventBase;
import com.hdkj.lt.core.bizms.modle.po.fault.FaultDistMappingFile;
import com.hdkj.lt.core.bizms.modle.po.fault.FaultPowerCutPvUsers;
import com.hdkj.lt.core.bizms.modle.po.fault.FaultPowerCutSwitch;
import com.hdkj.lt.core.bizms.mp.ArgTableNameHandler;
import com.hdkj.lt.core.log.exception.ExceptionErrorLogCast;
import com.hdkj.lt.core.log.model.param.ErrorLogParam;
import com.hdkj.lt.core.mq.client.RocketMQTemplate;
import com.hdkj.lt.core.mq.config.RocketMQProperties;
import com.hdkj.lt.core.mq.model.RocketMQMessageEntity;
import com.hdkj.lt.core.sys.dao.FhzgDistMappingFileMapper;
import com.hdkj.lt.core.sys.dao.FhzgOrganSuffixMapper;
import com.hdkj.lt.core.sys.model.dto.FhzgDistMappingFileDTO;
import com.hdkj.lt.modle.dto.simulation.FeederCheckRule;
import com.hdkj.lt.mq.entity.dto.AnalyzeDecudeParamDTO;
import com.hdkj.lt.mq.entity.dto.BrakerTransformerRelationDTO;
import com.hdkj.lt.mq.entity.dto.BreakerParamDTO;
import com.hdkj.lt.mq.entity.po.FhzgFaultPowerCut;
import com.hdkj.lt.mq.mapper.base.FeederTopoMapper;
import com.hdkj.lt.mq.mapper.base.FhzgReasoningPlatformMapper;
import com.hdkj.lt.mq.mapper.fault.FaultFhzgReasoningPlatformMapper;
import com.hdkj.lt.mq.service.base.ISvgFileInfoService;
import com.hdkj.lt.mq.service.fault.FaultFhzgReasoningPlatformService;
import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static com.hdkj.lt.base.constants.CommonConstant.THREE;

/**
 * @author zhuzhe
 * @since 2025-05-30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FaultFhzgReasoningPlatformServiceImpl implements FaultFhzgReasoningPlatformService {

    private final FaultFhzgReasoningPlatformMapper faultFhzgReasoningPlatformMapper;

    private final FhzgReasoningPlatformMapper fhzgReasoningPlatformMapper;

    private final RocketMQProperties rocketMQProperties;

    private final RocketMQTemplate rocketMQTemplate;

    private final FhzgOrganSuffixMapper fhzgOrganSuffixMapper;

    private final FeederTopoMapper feederTopoMapper;

    private final FaultPowerCutServiceService faultPowerCutServiceService;

    private final FaultDistMappingFileServiceImpl faultDistMappingFileService;

    private final FhzgDistMappingFileMapper fhzgDistMappingFileMapper;

    private final ISvgFileInfoService svgFileInfoService;


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public AnalyzeDecudeParamDTO getAnalyzeParam(Long faultId) {
        faultFhzgReasoningPlatformMapper.deleteFaultPowerCutSwitch(faultId);
        faultFhzgReasoningPlatformMapper.deleteFaultPowerCutUsers(faultId);

        FaultPowerCutSwitch faultPowerCutSwitch = new FaultPowerCutSwitch();
        AnalyzeDecudeParamDTO result = new AnalyzeDecudeParamDTO();
        // 查询故障信息
        FhzgFaultPowerCut faultPowerCut = faultPowerCutServiceService.getById(faultId);
        GridPdOutageEventBase gridPdOutageEventBase = faultFhzgReasoningPlatformMapper.getFaultInfoById(faultPowerCut.getFaultNo());
        String feeder = gridPdOutageEventBase.getRdtFeederId();
        result.setFeederId(feeder);

        BreakerParamDTO breakerParam1 = new BreakerParamDTO();
        String remark = "";

        BrakerTransformerRelationDTO relationDTO = new BrakerTransformerRelationDTO();
        /**
         * 查询topo树型结构
         */
        //动态切换表名
        //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByFaultIdOrLineId(faultId, null));
        List<BrakerTransformerRelationDTO> faultTopoTree = faultFhzgReasoningPlatformMapper.getFaultTree(feeder,gridPdOutageEventBase.getFaultEquipId(),Arrays.asList(DictConstants.KG_PSR_TYPE.split(",")));
        if (faultTopoTree != null && faultTopoTree.size() > 0) {
            for (BrakerTransformerRelationDTO dto : faultTopoTree) {
                if (DictConstants.FAULT_DIRECT_PSR_TYPE.contains(dto.getDwdPsrType())) {
                    breakerParam1.setSwitchType(dto.getDwdPsrType());
                    breakerParam1.setSwitchId(dto.getChildPsrId());
                    if (StringUtils.isNotEmpty(dto.getIsStartKg()) && "1".equals(dto.getIsStartKg())) {
                        breakerParam1.setDistribution(1);
                    } else {
                        breakerParam1.setDistribution(0);
                    }
                    relationDTO = dto;
                    break;
                } else {
                    continue;
                }
            }
        } else {
            log.warn("开关：{}、线路：{}，在topo表中不存在", gridPdOutageEventBase.getFaultEquipId(), gridPdOutageEventBase.getRdtFeederId());
            remark = "开关：" + gridPdOutageEventBase.getFaultEquipId() + "、线路：" + gridPdOutageEventBase.getRdtFeederId() + "，在topo表中不存在";
        }
        if (breakerParam1 == null) {
            log.warn("开关：{}、线路：{}，在topo表中没有找到满足类型的开关", gridPdOutageEventBase.getFaultEquipId(), gridPdOutageEventBase.getRdtFeederId());
            remark = "开关：" + gridPdOutageEventBase.getFaultEquipId() + "、线路：" + gridPdOutageEventBase.getRdtFeederId() + "，在topo表中没有找到满足类型的开关";
        }

        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        result.setTripBreaker(breakerParam1);
        if (gridPdOutageEventBase.getBeginTime() != null) {
            result.setStartTime(df.format(gridPdOutageEventBase.getBeginTime()));
//            result.setLoadTransferTime(df.format(gridPdOutageEventBase.getBeginTime()));
        }
        if (gridPdOutageEventBase.getEndTime() != null) {
            result.setStartTime(df.format(gridPdOutageEventBase.getEndTime()));
        }
        if (gridPdOutageEventBase.getAffectedEquipmentCnt() == 1) {
            log.warn("故障id：{} 是单配变停电，不调用计算推演平台", gridPdOutageEventBase.getId());
            remark = "故障id："+gridPdOutageEventBase.getId()+" 是单配变停电，不调用计算推演平台";
            ErrorLogParam errorLogParam = new ErrorLogParam()
                    .setErrorTime(LocalDateTime.now())
                    .setEventType(EventTypeEnum.FAULT.getCode())
                    .setEventId(faultId.toString())
                    .setStage(ErrorLogConstant.Stage.FAULT_OUTAGE_JOIN)
                    .setSourceSystem(ErrorLogConstant.SourceSystem.FHZG)
                    .setOperationStep(OperationStepEnum.FAULT.getName())
                    .setErrorCategory("单配变停电，不调用计算推演平台")
                    .setDetails("故障id："+gridPdOutageEventBase.getId()+" 是单配变停电，不调用计算推演平台");
            ExceptionErrorLogCast.cast(errorLogParam);
        }
        //获取对侧线路额定电流信息
        //动态切换表名
        //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByFaultIdOrLineId(faultId, null));
        //暂时不需要此参数，且格式错误
//        List<FeederCheckRule> feederCheckRule = feederTopoMapper
//                .getFeederCheckRule(result.getFeederId());
//        result.setFeederCheckRules(feederCheckRule);
        // 保存 数据到表里面
        faultPowerCutSwitch.setFaultId(faultId);
        if (result.getTripBreaker() != null ){
            faultPowerCutSwitch.setStartSwitch(result.getTripBreaker().getSwitchId());
            faultPowerCutSwitch.setIsFullLine(String.valueOf(result.getTripBreaker().getDistribution()));
        }
        faultPowerCutSwitch.setRemark(remark);
        if (StringUtils.isNotEmpty(remark)) {
            faultPowerCutSwitch.setStatus("0");
        } else {
            faultPowerCutSwitch.setStatus("1");
        }
        result.setIsolateBreakersList(new ArrayList<>());
        faultPowerCutSwitch.setAnalysisJson(JSON.toJSONString(result));
        Long id = IdUtil.getSnowflakeNextId();
        faultPowerCutSwitch.setId(id);
        faultFhzgReasoningPlatformMapper.saveFaultPowerCutSwitch(faultPowerCutSwitch);
        faultPowerCutServiceService.update(new LambdaUpdateWrapper<FhzgFaultPowerCut>().eq(FhzgFaultPowerCut::getId,faultPowerCutSwitch.getFaultId()).set(FhzgFaultPowerCut::getPowerOnSuccess,0));

        // 20250702 - 保存故障附件信息
//        this.saveFaultFile(feeder, faultId);

        if (result.getTripBreaker() != null && faultPowerCutSwitch.getStatus().equals("1")) {
            List<String> pbList = new ArrayList<>();
            //  判断是开关还是配变
            if (DictConstants.KG_PSR_TYPE.contains(relationDTO.getChildPsrType())) {
                // 查询开关下面的配变
                LambdaQueryWrapper<FeederTopo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(StringUtils.isNotEmpty(feeder), FeederTopo::getFeeder, feeder)
                        .eq(FeederTopo::getStartKgId, result.getTripBreaker().getSwitchId())
                        .in(FeederTopo::getPsrType, Arrays.asList(DictConstants.PB_PSR_TYPE.split(",")));

                //动态切换表名
                //*ztj ArgTableNameHandler.setArgument(fhzgOrganSuffixMapper.getOrganSuffixByFaultIdOrLineId(faultId, null));
                List<FeederTopo> leadoutBreakerList = fhzgReasoningPlatformMapper.getFeederTopo(wrapper);
                if (leadoutBreakerList != null && leadoutBreakerList.size() > 0) {
                    pbList = leadoutBreakerList.stream().map(FeederTopo::getPsrId).collect(Collectors.toList());
                }
            } else if (DictConstants.PB_PSR_TYPE.contains(relationDTO.getChildPsrType())) {
                pbList = Arrays.asList(result.getTripBreaker().getSwitchId());
            }

            if (pbList != null && pbList.size() > 0) {
                FaultPowerCutPvUsers powerCutPvUsers = new FaultPowerCutPvUsers();
                powerCutPvUsers.setFaultId(gridPdOutageEventBase.getId());
                // 根据配变保存故障用户
                faultFhzgReasoningPlatformMapper.savePowerCutUsers(powerCutPvUsers, pbList);
            }

        }

        try {
            // MQ消息订阅可以通过接口触发，当触发消息发送失败时不影响接口功能
            if (faultPowerCutSwitch != null && faultPowerCutSwitch.getStatus().equals("1") && rocketMQProperties.getEnabled()) {
                RocketMQMessageEntity messageEntity = RocketMQMessageEntity.builder()
                        .topicId(RocketMQConstants.TOPIC_ID_TO_ANALYSIS_RESULT_TICKET)
                        .cacheKey(RedisKeyConstants.ASYNC_QUEUE_TO_ANALYSIS_RESULT_TICKET)
                        .tag("2") // 1-计划停电，2-故障停电
                        .body(faultPowerCutSwitch.getFaultId()).build();
                rocketMQTemplate.sendAsyncMessage(messageEntity);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }

    // 故障SVG文件的获取并保存到 fhzg_fault_dist_mapping_file
    public void saveFaultFile(String lineId, Long faultId) {
        if (StrUtil.isBlank(lineId)) {
            throw new BusinessException("馈线编码为空");
        }
        List<String> idList = Lists.newArrayList(lineId);
        List<FhzgDistMappingFileDTO> fhzgDistMappingFileDTOS = fhzgDistMappingFileMapper.getMappingFileById(idList);

        // 排除掉动态一级联络图后的其他图入库
        List<FaultDistMappingFile> fileList = new ArrayList<>();
        if (CollUtil.isNotEmpty(fhzgDistMappingFileDTOS)) {
            fhzgDistMappingFileDTOS.forEach(e -> {
                FaultDistMappingFile planDistMappingFile = FaultDistMappingFile.builder()
                        .faultId(faultId)
                        .fileType(e.getFileType())
                        .fileId(e.getFileId())
                        .lineId(e.getLineId())
                        .createTime(LocalDateTime.now())
                        .delFlag("0").build();
                fileList.add(planDistMappingFile);
            });
        }
        if (CollUtil.isNotEmpty(fileList)) {
            faultDistMappingFileService.saveBatch(fileList);
            log.info("保存计划线路图信息完成planId:{},lineId:{}", faultId, lineId);
        }
        // 调用动态生成SVG文件并入库
        svgFileInfoService.getSvgGenerationFile(lineId, faultId, THREE);
    }
}
