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

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yeejoin.amos.boot.biz.common.utils.SnowflakeIdUtil;
import com.yeejoin.amos.boot.module.jg.api.entity.*;
import com.yeejoin.amos.boot.module.ymt.api.entity.*;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.EquipmentCategoryMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用于业务变更过程中的历史数据处理的service层
 */
@Slf4j
@Service
public class DataHandlerServiceImpl {

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private JgRegistrationHistoryServiceImpl registrationHistoryService;

    @Resource
    private JgInstallationNoticeServiceImpl installationNoticeService;

    @Resource
    private JgUseRegistrationServiceImpl useRegistrationService;

    @Resource
    private JgUseRegistrationEqServiceImpl useRegistrationEqService;

    @Resource
    private JgInstallationNoticeEqServiceImpl installationNoticeEqService;

    @Resource
    private IdxBizJgUseInfoServiceImpl useInfoService;

    @Resource
    private SnowflakeIdUtil sequence;

    @Resource
    private IdxBizJgProjectContraptionServiceImpl projectContraptionService;

    @Resource
    private IdxBizJgTechParamsPipelineServiceImpl techParamsPipelineService;

    @Resource
    private EquipmentCategoryMapper equipmentCategoryMapper;

    @Resource
    private IdxBizJgRegisterInfoServiceImpl registerInfoService;

    @Resource
    private IdxBizJgSupervisionInfoServiceImpl supervisionInfoService;

    @Resource
    private IdxBizJgFactoryInfoServiceImpl factoryInfoService;


    /**
     * 安装告知压力管道历史数据修复-详情中的设备列表修改为汇总表格式
     *
     * @return result
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean deviceListInFormWithInstallNotice() {
        List<JgInstallationNotice> noticeList = installationNoticeService.list(new LambdaQueryWrapper<JgInstallationNotice>()
                .eq(JgInstallationNotice::getEquCategoryCode, "8300"));

        List<JgRegistrationHistory> jgRegistrationHistories = noticeList.stream()
                .map(notice -> {
                    JgRegistrationHistory history = getRegistrationHistory(String.valueOf(notice.getSequenceNbr()));
                    if (history == null) return null;
                    try {
                        Map<String, Object> hisData = objectMapper.readValue(
                                history.getChangeData(),
                                new TypeReference<Map<String, Object>>() {
                                }
                        );
                        // 获取设备列表并处理每个设备信息
                        List<Map<String, Object>> deviceList = objectMapper.readValue(
                                objectMapper.writeValueAsString(hisData.get("deviceList")),
                                new TypeReference<ArrayList<Map<String, Object>>>() {
                                }
                        );
                        if (!ValidationUtil.isEmpty(deviceList)) {
                            List<Map<String, Object>> pipelineListInfo = installationNoticeService.getBaseMapper().getPipelineEquInfoByRecords(deviceList.stream().map(device -> String.valueOf(device.get("record"))).collect(Collectors.toList()));
                            // 更新处理后的数据回到 history 对象
                            hisData.put("deviceList", pipelineListInfo);
                        }
                        history.setChangeData(objectMapper.writeValueAsString(hisData)); // 更新 changeData 字段
                    } catch (Exception e) {
                        log.error("JSON 数据处理失败!", e);
                        throw new RuntimeException(e.getMessage());
                    }
                    return history;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        // 批量更新历史表数据
        registrationHistoryService.updateBatchById(jgRegistrationHistories);
        return Boolean.TRUE;
    }

    // 辅助方法：根据 DocumentId 获取历史记录
    private JgRegistrationHistory getRegistrationHistory(String documentId) {
        return registrationHistoryService.getBaseMapper().selectOne(
                new QueryWrapper<JgRegistrationHistory>().lambda()
                        .eq(JgRegistrationHistory::getCurrentDocumentId, documentId)
                        .eq(JgRegistrationHistory::getIsDelete, false)
        );
    }

    /**
     * 向新增的工程装置表刷入数据
     *
     * @return result
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean writeData2ProjectContraption() {

        // projectContraptionService.getBaseMapper().delete(null);

        List<IdxBizJgUseInfo> collect = useInfoService.lambdaQuery()
                .select(IdxBizJgUseInfo::getRecord, IdxBizJgUseInfo::getProjectContraption, IdxBizJgUseInfo::getUseUnitCreditCode, IdxBizJgUseInfo::getUseUnitName, IdxBizJgUseInfo::getIsIntoManagement)
                .isNotNull(IdxBizJgUseInfo::getProjectContraption)
                .ne(IdxBizJgUseInfo::getProjectContraption, "")
                .groupBy(IdxBizJgUseInfo::getProjectContraption, IdxBizJgUseInfo::getUseUnitCreditCode)
                .list().stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        log.info("查询到的工程装置集合: {}", JSON.toJSONString(collect));


        List<IdxBizJgProjectContraption> projectContraptionList = new ArrayList<>();
        Iterator<IdxBizJgUseInfo> iterator = collect.iterator();
        while (iterator.hasNext()) {
            IdxBizJgUseInfo useInfo = iterator.next();
            boolean isLast = !iterator.hasNext();

            String record = useInfo.getRecord();
            Boolean isIntoManagement = ObjectUtils.isEmpty(useInfo.getIsIntoManagement()) ? Boolean.FALSE : useInfo.getIsIntoManagement();
            String projectContraption = useInfo.getProjectContraption();
            String useUnitCreditCode = useInfo.getUseUnitCreditCode();

            Long sequenceNbr = sequence.nextId();

            List<String> installNotSeqs = installationNoticeEqService.lambdaQuery()
                    .eq(JgInstallationNoticeEq::getEquId, record)
                    .list().stream()
                    .filter(Objects::nonNull)
                    .map(JgInstallationNoticeEq::getEquipTransferId)
                    .collect(Collectors.toList());

            JgInstallationNotice installationNotice = installNotSeqs.isEmpty() ? null : installationNoticeService.lambdaQuery()
                    .in(JgInstallationNotice::getSequenceNbr, installNotSeqs)
                    .eq(JgInstallationNotice::getUseUnitCreditCode, useUnitCreditCode)
                    .eq(JgInstallationNotice::getNoticeStatus, FlowStatusEnum.TO_BE_FINISHED.getCode())
                    .list().stream()
                    .findFirst().orElse(null);

            List<String> useRegSeqs = useRegistrationEqService.lambdaQuery()
                    .eq(JgUseRegistrationEq::getEquId, record)
                    .list().stream()
                    .filter(Objects::nonNull)
                    .map(JgUseRegistrationEq::getEquipTransferId)
                    .collect(Collectors.toList());

            JgUseRegistration useRegistration = useRegSeqs.isEmpty() ? null : useRegistrationService.lambdaQuery()
                    .in(JgUseRegistration::getSequenceNbr, useRegSeqs)
                    .eq(JgUseRegistration::getUseUnitCreditCode, useUnitCreditCode)
                    .eq(JgUseRegistration::getStatus, FlowStatusEnum.TO_BE_FINISHED.getName())
                    .list().stream()
                    .findFirst().orElse(null);

            List<IdxBizJgUseInfo> useInfos = useInfoService.lambdaQuery()
                    .eq(IdxBizJgUseInfo::getProjectContraption, projectContraption)
                    .eq(IdxBizJgUseInfo::getUseUnitCreditCode, useUnitCreditCode)
                    .list();

            List<IdxBizJgTechParamsPipeline> idxBizJgTechParamsPipelines = useInfos.isEmpty() ? new ArrayList<>() : techParamsPipelineService
                    .lambdaQuery()
                    .in(IdxBizJgTechParamsPipeline::getRecord, useInfos.stream()
                            .map(IdxBizJgUseInfo::getRecord)
                            .collect(Collectors.toList()))
                    .list();

            double pipeLengthSum = idxBizJgTechParamsPipelines.stream()
                    .filter(Objects::nonNull)
                    .filter(pip -> Objects.nonNull(pip.getPipeLength()))
                    .mapToDouble(pipeline -> Double.parseDouble(pipeline.getPipeLength()))
                    .sum();

            IdxBizJgRegisterInfo registerInfo = registerInfoService.lambdaQuery()
                    .eq(IdxBizJgRegisterInfo::getRecord, useInfos
                            .stream().findFirst().orElse(new IdxBizJgUseInfo())
                            .getRecord())
                    .one();

            IdxBizJgSupervisionInfo supervisionInfo = supervisionInfoService.lambdaQuery()
                    .eq(IdxBizJgSupervisionInfo::getRecord, useInfos
                            .stream()
                            .findFirst().orElse(new IdxBizJgUseInfo())
                            .getRecord())
                    .one();

            IdxBizJgFactoryInfo factoryInfo = factoryInfoService.lambdaQuery()
                    .eq(IdxBizJgFactoryInfo::getRecord, useInfos
                            .stream()
                            .findFirst().orElse(new IdxBizJgUseInfo())
                            .getRecord())
                    .one();

            IdxBizJgProjectContraption idxBizJgProjectContraption = IdxBizJgProjectContraption.builder()
                    .projectContraption(projectContraption)
                    .projectContraptionNo(projectContraption)
                    .useUnitCreditCode(isIntoManagement ? (ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getUseUnitCreditCode()) : null)
                    .useUnitName(isIntoManagement ? (ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getUseUnitName()) : null)
                    .uscUnitCreditCode(isIntoManagement ? (ObjectUtils.isEmpty(useRegistration) ? (ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getInstallUnitCreditCode()) : null) : null)
                    .uscUnitName(isIntoManagement ? (ObjectUtils.isEmpty(useRegistration) ? (ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getInstallUnitName()) : null) : null)
                    .equList(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getEquListCode())
                    .equListName(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getEquList())
                    .equCategory(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getEquCategoryCode())
                    .equCategoryName(ObjectUtils.isEmpty(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getEquCategoryCode()) ? null : equipmentCategoryMapper.selectOne(new LambdaQueryWrapper<EquipmentCategory>().eq(EquipmentCategory::getCode, (ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getEquCategoryCode()))).getName())
                    .equDefine(ObjectUtils.isEmpty(registerInfo) ? null : registerInfo.getEquDefine())
                    .equDefineName(ObjectUtils.isEmpty(ObjectUtils.isEmpty(registerInfo) ? null : registerInfo.getEquDefine()) ? null : equipmentCategoryMapper.selectOne(new LambdaQueryWrapper<EquipmentCategory>().eq(EquipmentCategory::getCode, (ObjectUtils.isEmpty(registerInfo) ? null : registerInfo.getEquDefine()))).getName())
                    .content(null)
                    .pipelineLength(pipeLengthSum)
                    .productPhoto(ObjectUtils.isEmpty(registerInfo) ? null : registerInfo.getProductPhoto())
                    .otherAccessories(null)
                    .orgCode(ObjectUtils.isEmpty(supervisionInfo) ? null : supervisionInfo.getOrgBranchCode())
                    .orgName(ObjectUtils.isEmpty(supervisionInfo) ? null : supervisionInfo.getOrgBranchName())
                    .productQualificationCertificate(ObjectUtils.isEmpty(factoryInfo) ? null : factoryInfo.getProductQualityYieldProve())
                    .province(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getProvince())
                    .provinceName(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getProvinceName())
                    .city(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getCity())
                    .cityName(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getCityName())
                    .county(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getCounty())
                    .countyName(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getCountyName())
                    .street(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getStreet())
                    .streetName(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getStreetName())
                    .address(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getAddress())
                    .startLatitudeLongitude(ObjectUtils.isEmpty(idxBizJgTechParamsPipelines) ? null : idxBizJgTechParamsPipelines.get(0).getStartePosition())
                    .endLatitudeLongitude(ObjectUtils.isEmpty(idxBizJgTechParamsPipelines) ? null : idxBizJgTechParamsPipelines.get(0).getEndPosition())
                    .supervisoryCode(ObjectUtils.isEmpty(installationNotice) ? null : installationNotice.getSupervisoryCode())
                    .useRegistrationCode(ObjectUtils.isEmpty(useRegistration) ? null : useRegistration.getUseRegistrationCode())
                    .isIntoManagement(isIntoManagement)
                    .dataSource("jg")
                    .build();
            idxBizJgProjectContraption.setSequenceNbr(sequenceNbr);
            idxBizJgProjectContraption.setRecDate(new Date());
            idxBizJgProjectContraption.setIsDelete(Boolean.FALSE);
            projectContraptionList.add(idxBizJgProjectContraption);
            if (projectContraptionList.size() % 1000 == 0 || isLast) {
                projectContraptionService.saveBatch(projectContraptionList);
                projectContraptionList.clear();
            }

            useInfoService.lambdaUpdate()
                    .set(IdxBizJgUseInfo::getProjectContraptionId, sequenceNbr)
                    .eq(IdxBizJgUseInfo::getProjectContraption, projectContraption)
                    .eq(IdxBizJgUseInfo::getUseUnitCreditCode, useUnitCreditCode)
                    .update();

            if (!installNotSeqs.isEmpty()) {
                installationNoticeService.lambdaUpdate()
                        .set(JgInstallationNotice::getProjectContraptionId, sequenceNbr)
                        .in(JgInstallationNotice::getSequenceNbr, installNotSeqs)
                        .eq(JgInstallationNotice::getProjectContraption, projectContraption)
                        .eq(JgInstallationNotice::getUseUnitCreditCode, useUnitCreditCode)
                        .update();
            }

            if (!useRegSeqs.isEmpty()) {
                useRegistrationService.lambdaUpdate()
                        .set(JgUseRegistration::getProjectContraptionId, sequenceNbr)
                        .in(JgUseRegistration::getSequenceNbr, useRegSeqs)
                        .eq(JgUseRegistration::getProjectContraption, projectContraption)
                        .eq(JgUseRegistration::getUseUnitCreditCode, useUnitCreditCode)
                        .update();
            }

        }
        return Boolean.TRUE;
    }
}
