package com.yeejoin.amos.boot.module.jg.biz.edit.event.listener;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yeejoin.amos.boot.module.common.api.converter.CommonCustomConverter;
import com.yeejoin.amos.boot.module.jg.api.converter.EquDefineConverter;
import com.yeejoin.amos.boot.module.jg.api.dto.FieldChangeMeta;
import com.yeejoin.amos.boot.module.jg.api.entity.JgInstallationNotice;
import com.yeejoin.amos.boot.module.jg.api.entity.JgInstallationNoticeEq;
import com.yeejoin.amos.boot.module.jg.api.entity.JgUseRegistrationManage;
import com.yeejoin.amos.boot.module.jg.biz.edit.constant.ChangeFieldWatchConstants;
import com.yeejoin.amos.boot.module.jg.biz.edit.event.BaseBizDataChangeEvent;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.IdxBizJgProjectContraptionServiceImplService;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.JgInstallationNoticeEqServiceImpl;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.JgInstallationNoticeServiceImpl;
import com.yeejoin.amos.boot.module.jg.biz.service.impl.JgUseRegistrationManageServiceImpl;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgProjectContraption;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgRegisterInfo;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgSupervisionInfo;
import com.yeejoin.amos.boot.module.ymt.api.entity.IdxBizJgUseInfo;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgRegisterInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgSupervisionInfoMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.IdxBizJgUseInfoMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static com.yeejoin.amos.boot.module.jg.biz.service.impl.JgUseRegistrationManageServiceImpl.*;
import static org.apache.commons.lang3.StringUtils.defaultString;

@Component
@Slf4j
@RequiredArgsConstructor
public class ChangeEquipImpactCertListener {

    @Value("${change.log.deal.thread.number:1}")
    private int threadNumber;

    private final BlockingQueue<BaseBizDataChangeEvent> queue = new LinkedBlockingQueue<>();

    private final JgUseRegistrationManageServiceImpl jgUseRegistrationManageService;
    private final JgInstallationNoticeServiceImpl jgInstallationNoticeService;
    private final IdxBizJgProjectContraptionServiceImplService jgProjectContraptionService;
    private final JgInstallationNoticeEqServiceImpl jgInstallationNoticeEqService;
    private final IdxBizJgUseInfoMapper useInfoMapper;
    private final IdxBizJgRegisterInfoMapper registerInfoMapper;
    private final IdxBizJgSupervisionInfoMapper supervisionInfoMapper;

    /**
     * 事件监听：只把事件放入队列
     */
    @TransactionalEventListener(BaseBizDataChangeEvent.class)
    @Async
    public void onEvent(BaseBizDataChangeEvent event) {
        log.info("ChangeEquipImpactCertListener收到事件：{}", JSONObject.toJSONString(event));
        queue.add(event);
    }

    /**
     * 初始化线程池处理逻辑
     */
    @PostConstruct
    public void init() {
        ExecutorService executorService = Executors.newFixedThreadPool(threadNumber);
        IntStream.range(0, threadNumber).forEach(i -> executorService.execute(() -> {
            while (true) {
                try {
                    BaseBizDataChangeEvent event = queue.take();
                    handleEvent(event);
                } catch (Exception e) {
                    log.error("处理事件失败", e);
                }
            }
        }));
    }

    /**
     * 根据 bizType 路由处理逻辑
     */
    private void handleFieldChange(List<FieldChangeMeta> fieldChangeMetaList, JgUseRegistrationManage manage) {
        JSONObject certificatePrintTag = Optional.ofNullable(manage.getCertificatePrintTag())
                .map(JSONObject::parseObject)
                .orElse(new JSONObject());
        Set<String> keysToJson = new HashSet<>();
        for (FieldChangeMeta meta : fieldChangeMetaList) {
            String columnKey = meta.getColumnKey();
            if (!ChangeFieldWatchConstants.isWatched(columnKey)) {
                continue;
            }
            log.info("字段 [{}] 是影响字段", columnKey);
            for (String category : ChangeFieldWatchConstants.getMatchedCategories(columnKey)) {
                switch (category) {
                    case "USE_CERT":
                        this.updateUseCertField(manage, meta);
                        keysToJson.addAll(Arrays.asList(CERTIFICATE_NORMAL, CERTIFICATE_NESTED));
                        break;
                    case "USE_FLAG":
                    case "USE_FLAG_VEHICLE":
                        keysToJson.addAll(Arrays.asList(USE_FLAG_NORMAL, USE_FLAG_NESTED));
                        break;
                    case "PIPELINE_SUMMARY":
                    case "NOTICE":
                        keysToJson.add(EXPORT_SUMMARY_TABLE);
                        break;
                    case "USE_CYLINDER_SUMMARY":
                        this.updateUseCertField(manage, meta);
                        keysToJson.add(CERTIFICATE_NORMAL);
                        break;
                    default:
                        this.updateUseCertField(manage, meta);
                        log.warn("未知分类字段：[{}]", category);
                }
            }
        }
        for (String key : keysToJson) {
            Object value = certificatePrintTag.get(key);
            if (value instanceof Number && ((Number) value).intValue() == 2) {
                certificatePrintTag.put(key, 1);
            }
        }
        manage.setCertificatePrintTag(JSONObject.toJSONString(certificatePrintTag));
        jgUseRegistrationManageService.updateById(manage);
    }

    private void updateUseCertField(JgUseRegistrationManage manage, FieldChangeMeta meta) {
        String columnKey = meta.getColumnKey();
        String afterValue = Objects.toString(meta.getColumnNewValue(), null);
        String beforeValue = Objects.toString(meta.getColumnOldValue(), null);
        if (StringUtils.isBlank(afterValue)) {
            return;
        }
        switch (columnKey) {
            case "equDefine":
                manage.setEquDefineCode(afterValue);
                manage.setEquDefine(EquDefineConverter.getKeyByValue(afterValue));
                break;
            case "useOrgCode":
            case "useRegistrationCode":
                manage.setUseRegistrationCode(afterValue);
                break;
            case "carNumber":
                manage.setCarNumber(afterValue);
                break;
            case "city":
            case "county":
            case "street":
            case "factoryUseSiteStreet":
            case "address":
                if (!"unit".equals(manage.getManageType())) {
                    updateEquUseAddressByChangeId(manage, meta.getChangeId());
                }
                break;
            case "receiveCompanyCode":
                manage.setReceiveCompanyCode(afterValue);
                manage.setReceiveOrgName(CommonCustomConverter.CompanyCodeConverter.getNameByCode(afterValue));
                break;
            case "chargingMedium":
                manage.setFillingMedium(
                        Arrays.stream(manage.getFillingMedium().split(","))
                                .map(String::trim)
                                .map(v -> v.equals(meta.getDisplayOldValue()) ? meta.getDisplayNewValue() : v)
                                .distinct()
                                .collect(Collectors.joining(","))
                );
                break;
            case "singleBottleVolume":
                manage.setVolume(new BigDecimal(manage.getVolume())
                        .add(new BigDecimal(afterValue).subtract(new BigDecimal(beforeValue))).toPlainString());
                break;
            case "orgBranchName":
                this.updateUseRegistrationManagementByEquId(manage, meta.getChangeId());
                break;
            case "orgName":
                this.updateUseRegistrationManagementByProjectContraptionId(manage, meta.getChangeId());
                break;
            default:
                log.warn("未处理的USE_CERT字段：[{}]", columnKey);
                break;
        }
    }

    private void updateUseRegistrationManagementByEquId(JgUseRegistrationManage manage, Object record) {
        LambdaQueryWrapper<IdxBizJgSupervisionInfo> lambda = new QueryWrapper<IdxBizJgSupervisionInfo>().lambda().select(IdxBizJgSupervisionInfo::getOrgBranchCode, IdxBizJgSupervisionInfo::getOrgBranchName).eq(IdxBizJgSupervisionInfo::getRecord, record);
        IdxBizJgSupervisionInfo supervisionInfo = supervisionInfoMapper.selectOne(lambda);
        if (supervisionInfo == null) {
            return;
        }
        manage.setSuperviseOrgCode(supervisionInfo.getOrgBranchCode());
        manage.setSuperviseOrgName(supervisionInfo.getOrgBranchName());
    }

    private void updateUseRegistrationManagementByProjectContraptionId(JgUseRegistrationManage manage, Object projectId) {
        IdxBizJgProjectContraption projectContraption = jgProjectContraptionService.lambdaQuery().select(IdxBizJgProjectContraption::getOrgCode, IdxBizJgProjectContraption::getOrgName).eq(IdxBizJgProjectContraption::getSequenceNbr, projectId).one();
        if (projectContraption == null) {
            return;
        }
        manage.setSuperviseOrgCode(projectContraption.getOrgCode());
        manage.setSuperviseOrgName(projectContraption.getOrgName());
    }

    private void updateEquUseAddressByChangeId(JgUseRegistrationManage manage, Object changeId) {
        LambdaQueryWrapper<IdxBizJgUseInfo> lambda = new QueryWrapper<IdxBizJgUseInfo>().lambda();
        lambda.eq(IdxBizJgUseInfo::getRecord, String.valueOf(changeId));
        IdxBizJgUseInfo useInfo = useInfoMapper.selectOne(lambda);
        if (useInfo != null) {
            String fullAddress = String.join("",
                    defaultString(useInfo.getProvinceName()),
                    defaultString(useInfo.getCityName()),
                    defaultString(useInfo.getCountyName()),
                    defaultString(useInfo.getStreetName()),
                    defaultString(useInfo.getAddress())
            );
            manage.setEquUseAddress(fullAddress);
        } else {
            log.warn("未找到对应的使用信息记录，ChangeId: {}", changeId);
        }
    }

    /**
     * 根据 bizType 路由处理逻辑
     */
    private JSONObject handleFieldChangeProject(List<FieldChangeMeta> fieldChangeMetaList, JSONObject certificatePrintTag) {
        Set<String> keysToJson = fieldChangeMetaList.stream()
                .filter(v -> ChangeFieldWatchConstants.isWatched(v.getColumnKey()))
                .peek(v -> log.info("字段 [{}] 是影响字段", v.getColumnKey()))
                .flatMap(v -> ChangeFieldWatchConstants.getMatchedCategories(v.getColumnKey()).stream())
                .flatMap(category -> {
                    switch (category) {
                        case "NOTICE":
                        case "PIPELINE_SUMMARY":
                            return Stream.of(EXPORT_SUMMARY_TABLE);
                        default:
                            log.warn("未知分类字段：[{}]", category);
                            return Stream.empty();
                    }
                })
                .collect(Collectors.toSet());
        keysToJson.forEach(key -> {
            Object value = certificatePrintTag.get(key);
            if (value instanceof Number && ((Number) value).intValue() == 2) {
                certificatePrintTag.put(key, 1);
            }
        });
        return certificatePrintTag;
    }

    /**
     * 根据 bizType 路由处理逻辑
     */
    private void handleEvent(BaseBizDataChangeEvent event) {
        switch (event.getBizRelationData().getBizType()) {
            case "JG_USAGE_REGISTRATION":// 使用登记
                handleUsageRegistration(event);
                break;
            case "JG_INSTALLATION_NOTIFICATION":// 安装告知
                handleInstallationNotice(event);
                break;
            case "JG_NEW_EQUIP":// 新增设备
                handleNewEquipEdit(event);
                break;
            case "JG_NEW_PROJECT":// 新增装置
                handleNewProjectEdit(event.getData(), event.getBizRelationData().getBizId());
                break;
            default:
                handleDefaultRegistration(event);
                break;
        }
    }

    private void handleDefaultRegistration(BaseBizDataChangeEvent event) {
        String equId = Stream.concat(
                Optional.ofNullable(event.getBizRelationData().getProjectContraptionIds()).orElse(Collections.emptySet()).stream(),
                Optional.ofNullable(event.getBizRelationData().getRecords()).orElse(Collections.emptySet()).stream()
        ).findFirst().orElse(null);
        if (StringUtils.isBlank(equId)) {
            log.warn("[handleDefaultRegistration] 未找到设备ID，eventId={}", event.getBizRelationData().getBizId());
            return;
        }
        IdxBizJgRegisterInfo registerInfo = registerInfoMapper.selectOne(
                Wrappers.<IdxBizJgRegisterInfo>lambdaQuery()
                        .eq(IdxBizJgRegisterInfo::getRecord, equId)
        );
        if (registerInfo == null) {
            log.warn("[handleDefaultRegistration] 未查询到登记信息，equId={}", equId);
            return;
        }
        String useOrgCode = event.getData().stream()
                .filter(m -> "useOrgCode".equals(m.getColumnKey()))
                .map(FieldChangeMeta::getColumnOldValue)
                .findFirst()
                .orElse(registerInfo.getUseOrgCode());
        if (StringUtils.isBlank(useOrgCode)) {
            log.warn("[handleDefaultRegistration] useOrgCode 为空，equId={}", equId);
            return;
        }
        // 查询使用登记证管理信息
        JgUseRegistrationManage jgUseRegistrationManage = jgUseRegistrationManageService.lambdaQuery()
                .eq(JgUseRegistrationManage::getUseRegistrationCode, useOrgCode)
                .eq(JgUseRegistrationManage::getIsDelete, 0)
                .one();

        if (jgUseRegistrationManage == null) {
            log.info("[handleDefaultRegistration] 未找到使用登记证信息，useOrgCode={}", useOrgCode);
            return;
        }
        handleFieldChange(event.getData(), jgUseRegistrationManage);
        log.debug("[handleDefaultRegistration] 字段变更处理完成，useOrgCode={}", useOrgCode);
    }

    private void handleUsageRegistration(BaseBizDataChangeEvent event) {
        if (event.getBizRelationData().getBizIsFinished()){
            JgUseRegistrationManage jgUseRegistrationManage = jgUseRegistrationManageService.lambdaQuery()
                    .eq(JgUseRegistrationManage::getApplyNo, event.getBizRelationData().getBizId())
                    .eq(JgUseRegistrationManage::getIsDelete, 0)
                    .one();
            this.handleFieldChange(event.getData(), jgUseRegistrationManage);
            String equId = Stream.concat(
                    Optional.ofNullable(event.getBizRelationData().getProjectContraptionIds()).orElse(Collections.emptySet()).stream(),
                    Optional.ofNullable(event.getBizRelationData().getRecords()).orElse(Collections.emptySet()).stream()
            ).findFirst().orElse(null);
            if (event.getBizRelationData().getProjectContraptionIds() != null && !event.getBizRelationData().getProjectContraptionIds().isEmpty()) {
                this.handleNewProjectEdit(event.getData(), equId);
            }
            if (event.getBizRelationData().getRecords() != null && !event.getBizRelationData().getRecords().isEmpty()) {
                List<String> installationNoticeSeqList = jgInstallationNoticeEqService.lambdaQuery()
                        .eq(JgInstallationNoticeEq::getEquId, equId)
                        .list().stream()
                        .filter(Objects::nonNull)
                        .map(JgInstallationNoticeEq::getEquipTransferId)
                        .collect(Collectors.toList());
                JgInstallationNotice installationNotice = installationNoticeSeqList.isEmpty() ? null : jgInstallationNoticeService.lambdaQuery()
                        .in(JgInstallationNotice::getSequenceNbr, installationNoticeSeqList)
                        .eq(JgInstallationNotice::getUseUnitCreditCode, jgUseRegistrationManage.getUseRegistrationCode())
                        .eq(JgInstallationNotice::getNoticeStatus, FlowStatusEnum.TO_BE_FINISHED.getCode())
                        .list().stream()
                        .findFirst().orElse(null);
                if (installationNotice != null) {
                    JSONObject installationNoticePrintTag = Optional.ofNullable(installationNotice.getCertificatePrintTag())
                            .map(JSONObject::parseObject).orElse(new JSONObject());
                    JSONObject installationNoticeTagJson = this.handleFieldChangeProject(event.getData(), installationNoticePrintTag);
                    installationNotice.setCertificatePrintTag(JSONObject.toJSONString(installationNoticeTagJson));
                    jgInstallationNoticeService.updateById(installationNotice);
                }
            }
        }
        log.info("处理 useRegister 类型逻辑");
    }

    private void handleInstallationNotice(BaseBizDataChangeEvent event) {
        log.info("处理 installationNotice 类型逻辑");
        if (event.getBizRelationData().getBizIsFinished()){
            JgInstallationNotice jgInstallationNotice = jgInstallationNoticeService.lambdaQuery()
                    .eq(JgInstallationNotice::getApplyNo, event.getBizRelationData().getBizId())
                    .eq(JgInstallationNotice::getIsDelete, 0)
                    .one();
            JSONObject certificatePrintTag = Optional.ofNullable(jgInstallationNotice.getCertificatePrintTag())
                    .map(JSONObject::parseObject).orElse(new JSONObject());
            JSONObject tagJson = this.handleFieldChangeProject(event.getData(), certificatePrintTag);
            jgInstallationNotice.setCertificatePrintTag(JSONObject.toJSONString(tagJson));
            jgInstallationNoticeService.updateById(jgInstallationNotice);
            if (event.getBizRelationData().getProjectContraptionIds() != null && !event.getBizRelationData().getProjectContraptionIds().isEmpty()) {
                String projectContraptionId = Optional.of(event.getBizRelationData().getProjectContraptionIds())
                        .map(ids -> ids.iterator().next())
                        .orElse("");
                this.handleNewProjectEdit(event.getData(), projectContraptionId);
            }
        }
    }

    private void handleNewEquipEdit(BaseBizDataChangeEvent event) {
        log.info("处理 handleNewEquipEdit 类型逻辑");
        if (event.getBizRelationData().getBizIsFinished()){
            String useOrgCode = "";
            useOrgCode = event.getData().stream()
                    .filter(meta -> "useOrgCode".equals(meta.getColumnKey()))
                    .map(FieldChangeMeta::getColumnOldValue)
                    .findFirst()
                    .orElseGet(() -> {
                        LambdaQueryWrapper<IdxBizJgRegisterInfo> wrapper = new QueryWrapper<IdxBizJgRegisterInfo>().lambda();
                        wrapper.eq(IdxBizJgRegisterInfo::getRecord, event.getBizRelationData().getBizId());
                        IdxBizJgRegisterInfo registerInfo = registerInfoMapper.selectOne(wrapper);
                        return registerInfo != null ? registerInfo.getUseOrgCode() : null;
                    });
            JgUseRegistrationManage jgUseRegistrationManage = jgUseRegistrationManageService.lambdaQuery()
                    .eq(JgUseRegistrationManage::getUseRegistrationCode, useOrgCode)
                    .eq(JgUseRegistrationManage::getIsDelete, 0)
                    .one();
            this.handleFieldChange(event.getData(), jgUseRegistrationManage);
        }
    }

    private void handleNewProjectEdit(List<FieldChangeMeta> fieldChangeMetaList, String projectContraptionId) {
        log.info("处理 handleNewProjectEdit 类型逻辑");
        IdxBizJgProjectContraption projectContraption = jgProjectContraptionService.getById(projectContraptionId);
        JSONObject certificatePrintTag = Optional.ofNullable(projectContraption.getCertificatePrintTag())
                .map(JSONObject::parseObject)
                .orElseGet(JSONObject::new);
        JSONObject tagJson = this.handleFieldChangeProject(fieldChangeMetaList, certificatePrintTag);
        projectContraption.setCertificatePrintTag(tagJson.toJSONString());
        jgProjectContraptionService.updateById(projectContraption);
        String useOrgCode = fieldChangeMetaList.stream()
                .filter(meta -> "useRegistrationCode".equals(meta.getColumnKey()))
                .map(FieldChangeMeta::getColumnOldValue)
                .findFirst()
                .orElse(null);
        if (!ValidationUtil.isEmpty(useOrgCode)) {
            JgUseRegistrationManage jgUseRegistrationManage = jgUseRegistrationManageService.lambdaQuery()
                    .eq(JgUseRegistrationManage::getUseRegistrationCode, useOrgCode)
                    .eq(JgUseRegistrationManage::getIsDelete, 0)
                    .one();

            this.handleFieldChange(fieldChangeMetaList, jgUseRegistrationManage);
        }
    }
}
