package com.supervision.police.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.deepoove.poi.XWPFTemplate;
import com.supervision.common.constant.IndexRuleConstants;
import com.supervision.common.domain.R;
import com.supervision.common.utils.StringUtils;
import com.supervision.constant.JudgeResultEnum;
import com.supervision.neo4j.dto.ResultDTO;
import com.supervision.neo4j.utils.Neo4jUtils;
import com.supervision.police.domain.*;
import com.supervision.police.dto.*;
import com.supervision.police.dto.caseScore.CaseScore;
import com.supervision.police.dto.caseScore.CaseScoreDetailBuilder;
import com.supervision.police.dto.caseScore.CaseScoreDetailDTO;
import com.supervision.police.dto.indexRule.IndexRule;
import com.supervision.police.dto.indexRule.Operand;
import com.supervision.police.dto.indexRule.OperandUnit;
import com.supervision.police.dto.indexRule.RuleCondition;
import com.supervision.police.mapper.*;
import com.supervision.police.mybatis.RowSqlMapper;
import com.supervision.police.service.*;
import com.supervision.utils.CalculationUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Result;
import org.neo4j.driver.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.supervision.common.constant.IndexRuleConstants.*;
import static com.supervision.common.constant.NotePromptConstants.TYPE_STRUCTURAL_REASONING;

@Slf4j
@Service
@RequiredArgsConstructor
public class ModelServiceImpl implements ModelService {

    private final ResourceLoader resourceLoader;

    private final Driver driver;

    private final ModelCaseMapper modelCaseMapper;

    private final ModelAtomicIndexMapper modelAtomicIndexMapper;

    private final ModelAtomicResultMapper modelAtomicResultMapper;

    private final ModelIndexMapper modelIndexMapper;

    private final ModelIndexResultMapper modelIndexResultMapper;

    private final CasePersonMapper casePersonMapper;

    private final CaseEvidenceService caseEvidenceService;

    private final ModelAtomicResultService modelAtomicResultService;

    private final RowSqlMapper rowSqlMapper;

    private final ModelIndexService modelIndexService;

    private final CaseStatusManageService caseStatusManageService;

    private final ModelIndexAtomicRelationService modelIndexAtomicRelationService;

    private final NoteRecordService noteRecordService;

    @Autowired
    private NotePromptService notePromptService;

    @Autowired
    private EvidenceDirectoryService evidenceDirectoryService;

    private final EvidenceCategoryService evidenceCategoryService;

    @Override
    @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
    public R<?> analyseCase(AnalyseCaseDTO analyseCaseDTO) {

        ModelCase modelCase = modelCaseMapper.selectById(analyseCaseDTO.getCaseId());
        // 获取案件行为人ID
        CasePerson casePerson = casePersonMapper.selectOne(new LambdaQueryWrapper<CasePerson>()
                .eq(CasePerson::getCaseId, analyseCaseDTO.getCaseId())
                .eq(CasePerson::getCaseActorFlag, 1)
                .eq(CasePerson::getRoleCode, "1")
                .eq(StrUtil.isNotEmpty(analyseCaseDTO.getLawActorName()), CasePerson::getName, analyseCaseDTO.getLawActorName()));
        if (ObjectUtil.isEmpty(casePerson)) {
            throw new RuntimeException("未找到的行为人" + analyseCaseDTO.getLawActorName());
        }
        // 首先将原先的值进行赋值,设置到pre_result
        modelIndexResultMapper.updatePreResult(analyseCaseDTO.getCaseId());
        //原子指标
        List<ModelAtomicIndex> atomicIndices = modelAtomicIndexMapper.selectByCaseType(modelCase.getCaseType());
        // 存放原子指标的结果,key:原子指标ID,value:(key大指标ID,value:结果)
        Map<String, Map<String, String>> atomicResultMap = new HashMap<>();
        for (ModelAtomicIndex atomicIndex : atomicIndices) {
            //原子指标结果
            ModelAtomicResult result = new ModelAtomicResult();
            result.setCasePersonId(casePerson.getId());
            result.setCaseId(analyseCaseDTO.getCaseId());
            result.setAtomicId(atomicIndex.getId());
            //查询语句
            String ql = atomicIndex.getQueryLang();

            //原子指标结果表
            try {
                //查询图谱  index_source: 1人工定义  2数据库查询	3图谱生成	  4大模型
                if ("1".equals(atomicIndex.getIndexSource())) {
                    // list
                    manuallyDefinedCase(analyseCaseDTO, result, atomicIndex);
                } else if ("2".equals(atomicIndex.getIndexSource()) && StringUtils.isNotEmpty(ql)) {
                    //
                    analyseDataBaseCase(analyseCaseDTO, result, ql, casePerson.getName());
                } else if ("3".equals(atomicIndex.getIndexSource()) && StringUtils.isNotEmpty(ql)) {
                    // 使用知识图谱进行计算
                    analyseGraphCase(analyseCaseDTO, result, ql, casePerson.getName());
                } else if ("4".equals(atomicIndex.getIndexSource())) {
                    //
                } else if ("5".equals(atomicIndex.getIndexSource())) {
                    // todo: 结构化推理
                    //analyseStructuredInference(analyseCaseDTO, result);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            // 根据原子指标ID查model_index_atomic_relation表所有的指标ID
            List<ModelIndexAtomicRelation> relationList = modelIndexAtomicRelationService.lambdaQuery().eq(ModelIndexAtomicRelation::getAtomicIndexId, atomicIndex.getId()).list();
            for (ModelIndexAtomicRelation relation : relationList) {
                // 保存或更新原子指标结果表
                ModelAtomicResult exist = modelAtomicResultMapper.selectByCaseIdAndAtomicId(analyseCaseDTO.getCaseId(), casePerson.getId(), relation.getModelIndexId(), atomicIndex.getId());
                result.setIndexId(relation.getModelIndexId());
                if (exist == null) {
                    result.setId(null);
                    modelAtomicResultMapper.insert(result);
                } else {
                    result.setId(exist.getId());
                    modelAtomicResultMapper.updateById(result);
                }
                Map<String, String> indexMap = atomicResultMap.computeIfAbsent(
                        result.getAtomicId(),
                        k -> new HashMap<>() // 如果不存在则创建一个新的 HashMap
                );
                indexMap.put(relation.getModelIndexId(), result.getAtomicResult());
            }

        }
        // 最终计算得分
        calculateFinalScore(analyseCaseDTO, modelCase, atomicResultMap);
        caseStatusManageService.whenAnalyseCaseSuccess(analyseCaseDTO.getCaseId(), modelCase.getTotalScore());
        // 计算完成之后,把所有的笔录上传到模型
        noteRecordService.uploadFileToLangChainChat(analyseCaseDTO.getCaseId());
        return R.ok();
    }

    @Override
    public R<?> analyseCaseNew(AnalyseCaseDTO analyseCaseDTO) {
        log.info("数据准备阶段");
        String caseId = analyseCaseDTO.getCaseId();
        Map<String, Integer> typeScoreMap = new HashMap<>();
        // 查出案件信息
        ModelCase modelCase = modelCaseMapper.selectById(caseId);
        // 获取案件行为人ID
        CasePerson casePerson = casePersonMapper.selectOne(new LambdaQueryWrapper<CasePerson>()
                .eq(CasePerson::getCaseId, analyseCaseDTO.getCaseId())
                .eq(CasePerson::getCaseActorFlag, 1)
                .eq(CasePerson::getRoleCode, "1")
                .eq(StrUtil.isNotEmpty(analyseCaseDTO.getLawActorName()), CasePerson::getName, analyseCaseDTO.getLawActorName()));
        if (ObjectUtil.isEmpty(casePerson)) {
            throw new RuntimeException("未找到的行为人" + analyseCaseDTO.getLawActorName());
        }
        // 查出指标信息
        List<ModelIndex> modelIndices = modelIndexService.list(new LambdaQueryWrapper<ModelIndex>().eq(ModelIndex::getDataStatus, "1").eq(ModelIndex::getCaseType, modelCase.getCaseType()));
        // 查出原子指标信息
        List<ModelAtomicIndex> atomicIndices = modelAtomicIndexMapper.selectByCaseType(modelCase.getCaseType());
        // 查出提示词信息
        List<NotePrompt> notePrompts = notePromptService.list(new LambdaQueryWrapper<NotePrompt>().eq(NotePrompt::getType, TYPE_STRUCTURAL_REASONING));
        // 查出证据目录信息
        List<EvidenceDirectory> evidenceDirectories = evidenceDirectoryService.list(new LambdaQueryWrapper<EvidenceDirectory>().eq(EvidenceDirectory::getCaseId, caseId));
        // 查出证据信息
        List<CaseEvidence> caseEvidences = caseEvidenceService.list(new LambdaQueryWrapper<CaseEvidence>().eq(CaseEvidence::getCaseId, caseId));
        log.info("开始计算指标结果");
        // 遍历指标集合,处理每个指标的判断逻辑,得出结果
        modelIndices.forEach(modelIndex -> {
            log.info("开始计算指标ID:{},指标名称:{}", modelIndex.getId(), modelIndex.getName());
            IndexRule indexRule = modelIndex.getIndexRule();
            Set<Boolean> ruleConditionGroupResultList = new HashSet<>();
            if (indexRule != null) {
                indexRule.getRuleConditionGroupList().forEach(ruleConditionGroup -> {
                    Set<Boolean> ruleConditionResultSet = new HashSet<>();
                    ruleConditionGroup.getRuleConditionList().forEach(ruleCondition -> {
                        Set<Boolean> operandUnitResultSet = new HashSet<>();
                        // 得到当前指标要求的存在关系(存在或不存在)
                        boolean relationSymbol = IndexRuleConstants.EVALUATE_RESULT_EXIST.equals(ruleCondition.getRelationalSymbol());
                        ModelAtomicIndex modelAtomicIndex = atomicIndices.stream().filter(atomicIndex -> atomicIndex.getId().equals(ruleCondition.getAtomicIndexId())).findAny().orElse(null);
                        if (modelAtomicIndex == null && !OPERAND_TYPE_STRUCTURE.equals(ruleCondition.getIndexSource())) {
                            log.error("原子指标不存在,跳出当前循环。原子指标ID:{}", ruleCondition.getAtomicIndexId());
                            return;
                        }
                        // 定义原子指标结果共有属性
                        ModelAtomicResult result = new ModelAtomicResult();
                        result.setIndexId(modelIndex.getId());
                        result.setCasePersonId(casePerson.getId());
                        result.setCaseId(analyseCaseDTO.getCaseId());
                        result.setAtomicId(ruleCondition.getAtomicIndexId());
                        result.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
                        ModelAtomicResult exist = modelAtomicResultMapper.selectByCaseIdAndAtomicId(caseId, casePerson.getId(), modelIndex.getId(), ruleCondition.getAtomicIndexId());
                        if (exist != null) {
                            result.setId(exist.getId());
                        }
                        switch (ruleCondition.getIndexSource()) {
                            case OPERAND_TYPE_MANUAL:
                                operandUnitResultSet.add(relationSymbol == manualIndexAnalysis(ruleCondition.getAtomicIndexId(), caseId));
                                break;
                            case OPERAND_TYPE_DB:
                                operandUnitResultSet.add(relationSymbol == dbIndexAnalysis(caseId, modelAtomicIndex.getQueryLang(), result));
                                break;
                            case OPERAND_TYPE_GRAPH:
                                operandUnitResultSet.add(relationSymbol == graphIndexAnalysis(casePerson.getName(), modelAtomicIndex.getQueryLang(), analyseCaseDTO.getCaseId(), ruleCondition, result));
                                break;
                            case OPERAND_TYPE_STRUCTURE:
                                ruleCondition.getOperandUnitList().forEach(operandUnit -> operandUnitResultSet.add(structureIndexAnalysis(operandUnit, ruleCondition.getAtomicIndexId(), atomicIndices, notePrompts, evidenceDirectories, caseEvidences, result)));
                                break;
                            default:
                                break;
                        }
                        ruleConditionResultSet.add(CalculationUtil.calculateBooleanSet(operandUnitResultSet, ruleCondition.getLogic()));
                    });
                    ruleConditionGroupResultList.add(CalculationUtil.calculateBooleanSet(ruleConditionResultSet, ruleConditionGroup.getRowLogic()));
                });
            } else {
                log.error("指标规则不存在,跳出当前循环。指标ID:{}", modelIndex.getId());
                return;
            }
            // 计算指标结果并保存
            boolean result = CalculationUtil.calculateBooleanSet(ruleConditionGroupResultList, indexRule.getGroupLogic());
            ModelIndexResult modelIndexResult = new ModelIndexResult();
            modelIndexResult.setCaseId(caseId);
            modelIndexResult.setIndexId(modelIndex.getId());
            ModelIndexResult exist = modelIndexResultMapper.selectByCaseIdAndIndexId(analyseCaseDTO.getCaseId(), modelIndex.getId());
            if (exist != null) {
                modelIndexResult.setId(exist.getId());
            }
            modelIndexResult.setIndexResult(result ? "true" : "false");
            if (exist == null) {
                modelIndexResultMapper.insert(modelIndexResult);
            } else {
                modelIndexResultMapper.updateById(modelIndexResult);
            }
            if (result) {
                Integer score = typeScoreMap.getOrDefault(modelIndex.getIndexType(), 0);
                log.info("指标ID:{},指标类型:{},得分:{}分", modelIndex.getId(), modelIndex.getIndexType(), modelIndex.getIndexScore());
                typeScoreMap.put(modelIndex.getIndexType(), score + modelIndex.getIndexScore());
                log.info("当前类型总分:{}分", typeScoreMap.get(modelIndex.getIndexType()));
            }
        });
        Integer gx = typeScoreMap.getOrDefault("1", 0);
        Integer rz = typeScoreMap.getOrDefault("2", 0);
        Integer cz = typeScoreMap.getOrDefault("3", 0);
        int max = Integer.max(gx + rz, gx + cz);
        modelCase.setTotalScore(max);
        log.info("更新案件得分情况。最终得分:{}分(共性+入罪/共性+出罪 取最大值)。入罪:{}分。出罪:{}分。共性:{}分。", max, rz, cz, gx);
        caseStatusManageService.whenAnalyseCaseSuccess(analyseCaseDTO.getCaseId(), modelCase.getTotalScore());
        noteRecordService.uploadFileToLangChainChat(analyseCaseDTO.getCaseId());
        return R.ok();
    }

    /**
     * 人工定义指标分析
     *
     * @param atomicIndexId 原子指标ID
     * @param caseId        案件ID
     */
    private boolean manualIndexAnalysis(String atomicIndexId, String caseId) {
        boolean flag = false;
        List<ModelAtomicResult> modelAtomicResults = modelAtomicResultMapper.selectList(
                new LambdaQueryWrapper<ModelAtomicResult>().eq(ModelAtomicResult::getCaseId, caseId)
                        .eq(ModelAtomicResult::getAtomicId, atomicIndexId));
        if (modelAtomicResults != null && !modelAtomicResults.isEmpty()) {
            ModelAtomicResult modelAtomicResult = CollUtil.getFirst(modelAtomicResults);
            flag = EVALUATE_RESULT_EXIST.equals(modelAtomicResult.getAtomicResult());
        }
        return flag;
    }

    /**
     * 数据库查询指标分析
     *
     * @param caseId       案件ID
     * @param sql          查询语句
     * @param atomicResult 原子指标结果
     * @return 是否存在
     */
    private boolean dbIndexAnalysis(String caseId, String sql, ModelAtomicResult atomicResult) {
        Map<String, Object> params = new HashMap<>();
        params.put("caseId", caseId);
        List<Map> mapList = rowSqlMapper.selectList(sql, params, Map.class);
        boolean flag = false;
        if (mapList != null && !mapList.isEmpty()) {
            flag = true;
            String evidenceIds = mapList.stream().map(map -> map.get("id").toString()).collect(Collectors.joining(","));
            atomicResult.setEvidenceId(evidenceIds);
            atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
        }
        modelAtomicResultService.saveOrUpdate(atomicResult);
        return flag;
    }

    /**
     * 图谱查询指标分析
     *
     * @param casePersonName 行为人
     * @param queryLang      查询语句
     * @param caseId         案件ID
     * @param ruleCondition  规则条件
     * @param atomicResult   原子指标结果
     * @return 是否存在
     */
    private boolean graphIndexAnalysis(String casePersonName, String queryLang, String caseId, RuleCondition ruleCondition, ModelAtomicResult atomicResult) {
        boolean flag = false;
        Session session = driver.session();
        //图谱
        Map<String, Object> params = new HashMap<>();
        // 行为人
        params.put("lawActor", casePersonName);
        // 案号
        params.put("caseId", caseId);
        Result run;
        try {
            run = session.run(queryLang, params);
        } catch (Exception e) {
            log.error("图数据库查询出现错误,查询语句{},参数{}", queryLang, JSONUtil.toJsonStr(params), e);
            return flag;
        }
        List<ResultDTO> res = Neo4jUtils.getResultDTOList(run);
        int count = 0;
        if (!res.isEmpty()) {
            // 进行遍历,如果有存在的,就设置为有
            for (ResultDTO resultDTO : res) {
                if (StringUtils.isNotEmpty(resultDTO.getRelId())) {
                    //存在关系
                    count++;
                    atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
                    atomicResult.setRecordId(resultDTO.getRecordId());
                    // 在退出循环之前先合并相关文本分片id
                    String recordSplitIdJoin = res.stream().filter(r ->
                                    StringUtils.isNotEmpty(r.getRelId())
                                            && StringUtils.isNotEmpty(r.getRecordSplitId()))
                            .map(ResultDTO::getRecordSplitId).collect(Collectors.joining(","));
                    atomicResult.setRecordSplitId(recordSplitIdJoin);
                }
            }
        }
        if (CalculationUtil.evaluateExpression(String.valueOf(count), ruleCondition.getOperator(), ruleCondition.getValue())) {
            flag = true;
        }
        modelAtomicResultService.saveOrUpdate(atomicResult);
        return flag;
    }

    /**
     * 结构化查询指标分析
     *
     * @param operandUnit         操作单元
     * @param modelAtomicIndexId  原子指标ID
     * @param atomicIndices       原子指标集合
     * @param notePrompts         提示词集合
     * @param evidenceDirectories 证据目录集合
     * @param caseEvidences       证据集合
     * @param atomicResult        原子指标结果
     * @return 是否存在
     */
    private boolean structureIndexAnalysis(OperandUnit operandUnit, String modelAtomicIndexId, List<ModelAtomicIndex> atomicIndices, List<NotePrompt> notePrompts, List<EvidenceDirectory> evidenceDirectories, List<CaseEvidence> caseEvidences, ModelAtomicResult atomicResult) {
        Operand left = operandUnit.getLeftOperand();
        String operator = operandUnit.getOperator();
        Operand right = operandUnit.getRightOperand();
        boolean flag = false;
        ModelAtomicIndex modelAtomicIndex = atomicIndices.stream().filter(atomicIndex -> atomicIndex.getId().equals(modelAtomicIndexId)).findAny().orElse(null);
        if (modelAtomicIndex == null) {
            log.error("原子指标不存在。原子指标ID:{}", modelAtomicIndexId);
            return flag;
        }
        List<CaseEvidence> evidences = getEvidencesByPromptId(modelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts);
        ModelAtomicIndex rightModelAtomicIndex = null;
        if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) {
            log.info("右操作数为结构化查询,提前查好对应的原子指标");
            rightModelAtomicIndex = atomicIndices.stream().filter(atomicIndex -> atomicIndex.getId().equals(left.getAtomicIndexId())).findAny().orElse(null);
            if (rightModelAtomicIndex == null || StringUtils.isEmpty(rightModelAtomicIndex.getPromptId())) {
                log.error("原子指标不存在。原子指标ID:{}", left.getAtomicIndexId());
                return flag;
            }
        }
        if (!evidences.isEmpty()) {
            log.info("聚合类型为【{}】,右操作数操作类型为:【{}】", AGGREGATE_TYPE_SUM.equals(left.getAggregateType()) ? "求和" : AGGREGATE_TYPE_COUNT.equals(left.getAggregateType()) ? "计数" : "任一", OPERAND_TYPE_STRUCTURE.equals(right.getOperandType()) ? "结构化查询" : "值");
            switch (left.getAggregateType()) {
                case AGGREGATE_TYPE_SUM:
                    if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) {
                        List<CaseEvidence> rightEvidences = getEvidencesByPromptId(rightModelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts);
                        if (CalculationUtil.evaluateExpression(String.valueOf(getSumFromEvidences(left.getPropertyKey(), evidences)), operator, String.valueOf(getSumFromEvidences(right.getPropertyKey(), rightEvidences)))) {
                            atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(",")));
                            atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
                            modelAtomicResultService.saveOrUpdate(atomicResult);
                            return true;
                        }
                    } else if (OPERAND_TYPE_VALUE.equals(right.getOperandType())) {
                        if (CalculationUtil.evaluateExpression(String.valueOf(getSumFromEvidences(left.getPropertyKey(), evidences)), operator, right.getValue())) {
                            atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(",")));
                            atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
                            modelAtomicResultService.saveOrUpdate(atomicResult);
                            return true;
                        }
                    }
                    break;
                case AGGREGATE_TYPE_COUNT:
                    if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) {
                        List<CaseEvidence> rightEvidences = getEvidencesByPromptId(rightModelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts);
                        if (CalculationUtil.evaluateExpression(String.valueOf(evidences.size()), operator, String.valueOf(rightEvidences.size()))) {
                            atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(",")));
                            atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
                            modelAtomicResultService.saveOrUpdate(atomicResult);
                            return true;
                        }
                    } else if (OPERAND_TYPE_VALUE.equals(right.getOperandType())) {
                        if (CalculationUtil.evaluateExpression(String.valueOf(evidences.size()), operator, right.getValue())) {
                            atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(",")));
                            atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
                            modelAtomicResultService.saveOrUpdate(atomicResult);
                            return true;
                        }
                    }
                    break;
                case AGGREGATE_TYPE_ANY:
                    if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) {
                        List<CaseEvidence> rightEvidences = getEvidencesByPromptId(rightModelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts);
                        Set<String> leftValueSet = getValueSetFromEvidences(left, evidences);
                        Set<String> rightValueSet = getValueSetFromEvidences(right, rightEvidences);
                        // 使用CalculationUtil.evaluateExpression方法遍历比较leftValueSet和rightValueSet的任一值,一旦有一个满足(返回true),则return true
                        if (leftValueSet.stream().anyMatch(leftValue -> rightValueSet.stream().anyMatch(rightValue -> CalculationUtil.evaluateExpression(leftValue, operator, rightValue)))) {
                            atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(",")));
                            atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
                            modelAtomicResultService.saveOrUpdate(atomicResult);
                            return true;
                        }
                    } else if (OPERAND_TYPE_VALUE.equals(right.getOperandType())) {
                        Set<String> leftValueSet = getValueSetFromEvidences(left, evidences);
                        if (leftValueSet.stream().anyMatch(leftValue -> CalculationUtil.evaluateExpression(leftValue, operator, right.getValue()))) {
                            atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(",")));
                            atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
                            modelAtomicResultService.saveOrUpdate(atomicResult);
                            return true;
                        }
                    }
                    break;
                default:
                    break;
            }
        } else {
            log.error("证据不存在。提示词ID:{}", modelAtomicIndex.getPromptId());
        }
        return flag;
    }

    private Double getSumFromEvidences(String propertyKey, List<CaseEvidence> evidences) {
        AtomicReference<Double> sum = new AtomicReference<>(0.0);
        if (evidences != null && !evidences.isEmpty()) {
            evidences.forEach(e -> {
                List<NotePromptExtractAttributesDto> properties = e.getProperty();
                if (properties != null && !properties.isEmpty()) {
                    properties.forEach(p -> {
                        if (p.getAttrName().equals(propertyKey)) {
                            if (StringUtils.isNotEmpty(p.getAttrValue())) {
                                sum.updateAndGet(v -> v + NumberUtil.parseDouble(p.getAttrValue()));
                            }
                        }
                    });
                }
            });
        }
        return sum.get();
    }

    private Set<String> getValueSetFromEvidences(Operand operand, List<CaseEvidence> evidences) {
        Set<String> valueSet = new HashSet<>();
        evidences.forEach(e -> {
            List<NotePromptExtractAttributesDto> properties = e.getProperty();
            if (properties != null && !properties.isEmpty()) {
                properties.forEach(p -> {
                    if (p.getAttrName().equals(operand.getPropertyKey())) {
                        if (StringUtils.isNotEmpty(p.getAttrValue())) {
                            valueSet.add(p.getAttrValue());
                        }
                    }
                });
            }
        });
        return valueSet;
    }

    /**
     * 根据原子指标ID获取证据集合
     *
     * @param promptId            提示词ID
     * @param caseEvidences       全量案件证据集合
     * @param evidenceDirectories 证据目录集合
     * @param notePrompts         提示词集合
     * @return 证据集合
     */
    private static List<CaseEvidence> getEvidencesByPromptId(String promptId, List<CaseEvidence> caseEvidences, List<EvidenceDirectory> evidenceDirectories, List<NotePrompt> notePrompts) {
        List<CaseEvidence> evidences = new ArrayList<>();
        NotePrompt notePrompt = notePrompts.stream().filter(n -> n.getId().equals(promptId)).findAny().orElse(null);
        if (notePrompt == null) {
            log.error("提示词不存在。提示词ID:{}", promptId);
            return evidences;
        }
        List<EvidenceDirectory> directories = evidenceDirectories.stream().filter(e -> e.getCategoryId().equals(notePrompt.getEvidenceCategoryId())).toList();
        List<String> directoryIds = directories.stream().map(EvidenceDirectory::getId).toList();
        evidences = caseEvidences.stream().filter(e -> directoryIds.contains(e.getDirectoryId())).toList();
        return evidences;
    }

    /**
     * 手动定义原子指标处理
     *
     * @param analyseCaseDTO 案件信息
     * @param result         原子指标结果
     * @param atomicIndex    原子指标
     */
    private void manuallyDefinedCase(AnalyseCaseDTO analyseCaseDTO, ModelAtomicResult result, ModelAtomicIndex atomicIndex) {
        List<ModelAtomicResult> modelAtomicResults = modelAtomicResultMapper.selectList(
                new LambdaQueryWrapper<ModelAtomicResult>().eq(ModelAtomicResult::getCaseId, analyseCaseDTO.getCaseId())
                        .eq(ModelAtomicResult::getAtomicId, atomicIndex.getId()));

        if (CollUtil.isEmpty(modelAtomicResults)) {
            log.info("manuallyDefinedCase:根据caseId:{},atomicId:{}未找到原子指标结果", analyseCaseDTO.getCaseId(), atomicIndex.getId());
            return;
        }
        if (CollUtil.size(modelAtomicResults) > 0) {
            log.warn("manuallyDefinedCase:根据caseId:{},atomicId:{}找到多个原子指标结果", analyseCaseDTO.getCaseId(), atomicIndex.getId());
        }
        ModelAtomicResult modelAtomicResult = CollUtil.getFirst(modelAtomicResults);


        result.setAtomicResult(modelAtomicResult.getAtomicResult());
    }

    @Override
    public CaseScoreDetailDTO caseScoreDetail(String caseId) {
        Assert.notEmpty(caseId, "案件id不能为空");

        CaseScoreDetailBuilder caseScoreDetailBuilder = new CaseScoreDetailBuilder()
                .setOllamaChatClient(null)
                .setMapper(modelCaseMapper, casePersonMapper, modelAtomicIndexMapper,
                        modelIndexResultMapper, modelIndexMapper, modelAtomicResultMapper);

        caseScoreDetailBuilder.loadCaseScoreDetail(caseId);
        List<EvidenceDirectoryDTO> evidenceDirectoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId);
        List<EvidenceCategoryDTO> evidenceCategoryDTOS = evidenceCategoryService.listCategoryTree(caseScoreDetailBuilder.getCaseType());
        caseScoreDetailBuilder.setEvidence(new EvidenceDirectoryDTO(evidenceDirectoryDTOS), new EvidenceCategoryDTO(evidenceCategoryDTOS));
        return caseScoreDetailBuilder.build();
    }

    @Override
    public CaseScore caseScoreByCaseId(String caseId) {
        CaseScoreDetailBuilder caseScoreDetailBuilder = new CaseScoreDetailBuilder()
                .setOllamaChatClient(null)
                .setMapper(modelCaseMapper, casePersonMapper, modelAtomicIndexMapper,
                        modelIndexResultMapper, modelIndexMapper, modelAtomicResultMapper);

        caseScoreDetailBuilder.loadCaseScoreDetail(caseId);
        CaseScore caseScore = new CaseScore();
        caseScore.setCommonScore(caseScoreDetailBuilder.getCommonScore());
        caseScore.setCrimeScore(caseScoreDetailBuilder.getCrimeScore());
        caseScore.setCrimeOutScore(caseScoreDetailBuilder.getCrimeOutScore());
        return caseScore;
    }

    @Override
    public CaseStatus getCaseDateStatus(String caseId) {

        Assert.notEmpty(caseId, "案件id不能为空");

        ModelCase modelCase = modelCaseMapper.selectById(caseId);
        Assert.notNull(modelCase, "案件不存在");

        return new CaseStatus(modelCase.getCaseDataStatus(), modelCase.getCaseAnalysisStatus());

    }

    @Override
    public void exportCaseScoreDetail(String caseId, HttpServletResponse response) {
        CaseScoreDetailDTO caseScoreDetailDTO = caseScoreDetail(caseId);
        caseScoreDetailDTO.buildDesc();

        // 加载模板
        Resource resource = resourceLoader.getResource("classpath:template/case_detail.docx");
        InputStream inputStream = null;
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(caseScoreDetailDTO.getCaseName() + ".docx", StandardCharsets.UTF_8));
            inputStream = resource.getInputStream();
            XWPFTemplate template = XWPFTemplate.compile(inputStream).render(caseScoreDetailDTO);
            template.writeAndClose(response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("exportCaseScoreDetail: inputStream.close() error", e);
                }
            }
        }
    }

    /**
     * 最终计算得分
     */
    private void calculateFinalScore(AnalyseCaseDTO analyseCaseDTO, ModelCase modelCase, Map<String, Map<String, String>> atomicResultMap) {
        // 根据案件类型获取所有的指标
        List<ModelIndex> modelIndices = modelIndexService.list(new LambdaQueryWrapper<ModelIndex>().eq(ModelIndex::getDataStatus, "1").eq(ModelIndex::getCaseType, modelCase.getCaseType()));
        Map<String, Integer> typeScoreMap = new HashMap<>();
        for (ModelIndex modelIndex : modelIndices) {
            ModelIndexResult result = new ModelIndexResult();
            result.setCaseId(analyseCaseDTO.getCaseId());
            result.setIndexId(modelIndex.getId());
            Set<String> atomicIds = new HashSet<>();
            // 判断逻辑是否为空,如果不为空,就根据判断逻辑进行判断
            if (StringUtils.isNotEmpty(modelIndex.getJudgeLogic())) {
                List<JudgeLogic> judgeLogics = JSONUtil.toList(modelIndex.getJudgeLogic(), JudgeLogic.class);
                if (CollUtil.isNotEmpty(judgeLogics)) {
                    boolean finalJudgeResult = false;
                    // 遍历组
                    for (int i = 0; i < judgeLogics.size(); i++) {
                        // 组内结果
                        boolean innerGroupJudge = false;
                        JudgeLogic logic = judgeLogics.get(i);
                        // 获取组之间的的判断逻辑
                        String rowLogic = logic.getRowLogic();
                        // 首先对组内进行判断,判断组内的结果
                        List<AtomicData> atomicData = logic.getAtomicData();
                        for (int j = 0; j < atomicData.size(); j++) {
                            AtomicData data = atomicData.get(j);
                            atomicIds.add(data.getAtomicIndex());
                            // 先找到原子指标对应的大指标的结果
                            Map<String, String> atomicIndexMap = atomicResultMap.get(data.getAtomicIndex());
                            String atomicIndexResult;
                            if (CollUtil.isEmpty(atomicIndexMap)) {
                                atomicIndexResult = JudgeResultEnum.UNKNOWN.getCode();
                            } else {
                                // 这里可能不存在,如果未找到,就默认为false
                                atomicIndexResult = atomicIndexMap.getOrDefault(modelIndex.getId(), JudgeResultEnum.UNKNOWN.getCode());
                            }
                            String relationalSymbol = data.getRelationalSymbol();
                            JudgeResultEnum instance = JudgeResultEnum.getInstance(relationalSymbol);
                            boolean ato = StrUtil.equals(atomicIndexResult, instance.getCode());
                            if (j == 0) {
                                innerGroupJudge = ato;
                            } else {
                                if ("1".equals(rowLogic)) {
                                    innerGroupJudge = innerGroupJudge && ato;
                                } else if ("2".equals(rowLogic)) {
                                    innerGroupJudge = innerGroupJudge || ato;
                                }
                            }
                        }
                        // 组间进行判断
                        String groupLogic = logic.getGroupLogic();
                        if (i == 0) {
                            finalJudgeResult = innerGroupJudge;
                        } else {
                            // 如果组间判断为1 与,则进行与操作
                            if ("1".equals(groupLogic)) {
                                finalJudgeResult = finalJudgeResult && innerGroupJudge;
                                // 如果组间判断为或,则进行或操作
                            } else if ("2".equals(groupLogic)) {
                                finalJudgeResult = finalJudgeResult || innerGroupJudge;
                            }
                        }
                    }
                    result.setIndexResult(finalJudgeResult ? "true" : "false");
                    result.setAtomicIds(StringUtils.join(atomicIds, ","));
                }
            }
            // 最后保存结果
            ModelIndexResult exist = modelIndexResultMapper.selectByCaseIdAndIndexId(analyseCaseDTO.getCaseId(), modelIndex.getId());
            if (exist == null) {
                modelIndexResultMapper.insert(result);
            } else {
                result.setId(exist.getId());
                modelIndexResultMapper.updateById(result);
            }

            if ("true".equals(result.getIndexResult())) {
                Integer orDefault = typeScoreMap.getOrDefault(modelIndex.getIndexType(), 0);
                typeScoreMap.put(modelIndex.getIndexType(), orDefault + modelIndex.getIndexScore());
            }
        }
        // 计算分数 共性+入罪/共性+出罪 取最大值
        Integer gx = typeScoreMap.getOrDefault("1", 0);
        Integer rz = typeScoreMap.getOrDefault("2", 0);
        Integer cz = typeScoreMap.getOrDefault("3", 0);
        int max = Integer.max(gx + rz, gx + cz);
        modelCase.setTotalScore(max);
        modelCaseMapper.updateById(modelCase);
    }

    private void analyseGraphCase(AnalyseCaseDTO analyseCaseDTO, ModelAtomicResult result, String ql, String caseActorName) {
        Session session = driver.session();
        //图谱
        int i = 1;
        Map<String, Object> params = new HashMap<>();
        // 行为人
        params.put("lawActor", caseActorName);
        // 案号
        params.put("caseId", analyseCaseDTO.getCaseId());
        // 参数中是否传了受害人
        String lawPartys = analyseCaseDTO.getLawParty();
        // 如果有受害人的话就进行分割
        String[] split = StringUtils.isEmpty(lawPartys) ? new String[0] : lawPartys.split(",");
        if (ql.contains("$lawParty") && split.length > 1) {
            i = split.length;
        }
        // 只有有符合的,就认为符合,不进行遍历了
        judge:
        for (int j = 0; j < i; j++) {
            if (split.length > 0) {
                params.put("lawParty", split[j]);
            }
            Result run;
            try {
                run = session.run(ql, params);
            } catch (Exception e) {
                result.setAtomicResult("-1");
                log.error("图数据库查询出现错误,查询语句{},参数{}", ql, JSONUtil.toJsonStr(params), e);
                return;
            }

            List<ResultDTO> res = Neo4jUtils.getResultDTOList(run);
            if (res.isEmpty()) {
                result.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
            } else {
                // 设置为0,不存在
                result.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
                // 进行遍历,如果有存在的,就设置为有
                for (ResultDTO resultDTO : res) {
                    if (StringUtils.isNotEmpty(resultDTO.getRelId())) {
                        //存在关系
                        result.setAtomicResult(JudgeResultEnum.EXIST.getCode());
                        result.setRecordId(resultDTO.getRecordId());

                        // 在退出循环之前先合并相关文本分片id
                        String recordSplitIdJoin = res.stream().filter(r ->
                                        StringUtils.isNotEmpty(r.getRelId())
                                                && StringUtils.isNotEmpty(r.getRecordSplitId()))
                                .map(ResultDTO::getRecordSplitId).collect(Collectors.joining(","));
                        result.setRecordSplitId(recordSplitIdJoin);
                        // 如果只要存在,就不进行校验了,直接跳出循环
                        break judge;
                    }
                }
            }
        }
    }


    /**
     * 分析数据库类型的原子信息
     *
     * @param analyseCaseDTO
     * @param result
     * @param sql
     */
    private void analyseDataBaseCase(AnalyseCaseDTO analyseCaseDTO, ModelAtomicResult result, String sql, String caseActorName) {

        Map<String, Object> params = new HashMap<>();
        params.put("caseId", result.getCaseId());
        params.put("evidenceName", analyseCaseDTO.getEvidenceName());
        params.put("provider", null);
        params.put("party_a", caseActorName);
        params.put("party_b", analyseCaseDTO.getLawParty());
        boolean success = false;
        if (modelIndexService.checkSql(sql)) {
            success = parseResult(rowSqlMapper.selectList(sql, params, Map.class));
        }
        result.setAtomicResult(success ? JudgeResultEnum.EXIST.getCode() : JudgeResultEnum.NOT_EXIST.getCode());


    }

    /**
     * 执行结果分析:
     * 1. 如果查询出的结果只有一行,判断列数是否大于1,如果大于1,返回真,如果=1,继续判断值是否大于0,如果大于0,返回真,如果=0,返回假
     * 2. 如果查询出的结果大于一行,则返回真
     *
     * @param mapList 查询结果
     * @return
     */
    private boolean parseResult(List<Map> mapList) {

        if (CollUtil.isEmpty(mapList)) {
            return false;
        }

        if (CollUtil.size(mapList) > 1) {
            return true;
        }

        Map firstRow = CollUtil.getFirst(mapList);
        if (firstRow.size() == 1 && CollUtil.size(firstRow.values()) == 1) {
            Object first = CollUtil.getFirst(firstRow.values());
            if (NumberUtil.isNumber(first.toString())) {
                return NumberUtil.parseInt(first.toString()) > 0;
            }
        }
        return true;
    }
}