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.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.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.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 javax.annotation.PostConstruct;
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;

    /**
     * 事件监听：只把事件放入队列
     */
    @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":
                        keysToJson.add(CERTIFICATE_NORMAL);
                        break;
                    default:
                        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);
        if (StringUtils.isBlank(afterValue)) {
            return;
        }
        switch (columnKey) {
            case "equDefine":
                manage.setEquDefineCode(afterValue);
                manage.setEquDefine(EquDefineConverter.getKeyByValue(afterValue));
                break;
            case "useOrgCode":
                manage.setUseRegistrationCode(afterValue);
                break;
            case "carNumber":
                manage.setCarNumber(afterValue);
                break;
            case "city":
            case "county":
            case "street":
            case "address":
                if (!"unit".equals(manage.getManageType())) {
                    updateEquUseAddressByChangeId(manage, meta.getChangeId());
                }
                break;
            default:
                log.warn("未处理的USE_CERT字段：[{}]", columnKey);
                break;
        }
    }

    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) {
        if (event.getBizRelationData().getBizIsFinished()){
                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);
                LambdaQueryWrapper<IdxBizJgRegisterInfo> queryRegisterWrapper = new QueryWrapper<IdxBizJgRegisterInfo>().lambda();
                queryRegisterWrapper.eq(IdxBizJgRegisterInfo::getRecord, equId);
                IdxBizJgRegisterInfo registerInfo = registerInfoMapper.selectOne(queryRegisterWrapper);
            JgUseRegistrationManage jgUseRegistrationManage = jgUseRegistrationManageService.lambdaQuery()
                    .eq(JgUseRegistrationManage::getUseRegistrationCode, registerInfo.getUseOrgCode())
                    .eq(JgUseRegistrationManage::getIsDelete, 0)
                    .one();
            this.handleFieldChange(event.getData(), jgUseRegistrationManage);
        }
    }

    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 = "";
            for (FieldChangeMeta meta : event.getData()) {
                String columnKey = meta.getColumnKey();
                if (columnKey.equals("useOrgCode")){
                    useOrgCode = meta.getColumnOldValue();
                }else{
                    LambdaQueryWrapper<IdxBizJgRegisterInfo> queryRegisterWrapper = new QueryWrapper<IdxBizJgRegisterInfo>().lambda();
                    queryRegisterWrapper.eq(IdxBizJgRegisterInfo::getRecord, event.getBizRelationData().getBizId());
                    IdxBizJgRegisterInfo registerInfo = registerInfoMapper.selectOne(queryRegisterWrapper);
                    useOrgCode = registerInfo.getUseOrgCode();
                }
            }
            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).orElse(new JSONObject());
            JSONObject tagJson = this.handleFieldChangeProject(fieldChangeMetaList, certificatePrintTag);
        projectContraption.setCertificatePrintTag(JSONObject.toJSONString(tagJson));
        jgProjectContraptionService.updateById(projectContraption);
    }
}
