package com.ruoyi.basic.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.domain.dto.AnswerSubmitDTO;
import com.ruoyi.basic.domain.dto.ConstitutionScoreDTO;
import com.ruoyi.basic.domain.model.*;
import com.ruoyi.basic.domain.question.*;
import com.ruoyi.basic.mapper.*;
import com.ruoyi.basic.service.QuestionRuleService;
import com.ruoyi.basic.service.QuestionnaireService;
import com.ruoyi.common.utils.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class QuestionnaireServiceImpl extends ServiceImpl<QuestionAnswerSheetMapper, QuestionAnswerSheet>
        implements QuestionnaireService {

    private final QuestionSurveyMapper surveyMapper;
    private final QuestionConstitutionTypeMapper constitutionTypeMapper;
    private final QuestionQuestionMapper questionMapper;
    private final QuestionOptionMapper optionMapper;
    private final QuestionAnswerDetailMapper answerDetailMapper;
    private final QuestionConstitutionScoreMapper constitutionScoreMapper;
    private final QuestionRuleService ruleService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AnswerResultVO submitAnswers(AnswerSubmitDTO dto, HttpServletRequest request) {
        // 1. 校验问卷
        QuestionSurvey survey = surveyMapper.selectById(dto.getSurveyId());
        if (survey == null || survey.getStatus() != 1) {
            throw new RuntimeException("问卷不存在或未发布");
        }

        // 2. 保存答卷主表
        QuestionAnswerSheet sheet = new QuestionAnswerSheet();
        sheet.setSurveyId(dto.getSurveyId());
        sheet.setUserId(SecurityUtils.getAppLoginUser().getAppUserId());
        sheet.setSessionId(StrUtil.blankToDefault(dto.getSessionId(), UUID.randomUUID().toString()));
        sheet.setSubmitTime(LocalDateTime.now());
        sheet.setIpAddress(ServletUtil.getClientIP(request));
        this.save(sheet);
        Long sheetId = sheet.getId();

        // 3. 批量保存答案明细
        List<QuestionAnswerDetail> details = dto.getAnswers().stream()
                .map(item -> {
                    QuestionAnswerDetail detail = new QuestionAnswerDetail();
                    detail.setSheetId(sheetId);
                    detail.setQuestionId(item.getQuestionId());
                    detail.setOptionId(item.getOptionId());
                    return detail;
                }).collect(Collectors.toList());
        answerDetailMapper.insertBatch(details);

        // 4. 计算各模块总分
        List<QuestionConstitutionScore> scores = computeConstitutionScores(sheetId);
        if (CollUtil.isNotEmpty(scores)) {
            constitutionScoreMapper.insertBatch(scores);
        } else {
            scores = Collections.emptyList();
        }

        // 5. 获取所有模块信息（用于构建上下文和VO）
        // 获取所有模块信息
        List<QuestionConstitutionType> constitutions = constitutionTypeMapper.selectList(null);
        Map<Long, QuestionConstitutionType> constitutionMap = constitutions.stream()
                .collect(Collectors.toMap(QuestionConstitutionType::getId, c -> c));
        // 构建得分映射（体质ID -> 总分）
        Map<Long, Integer> scoreById = scores.stream()
                .collect(Collectors.toMap(QuestionConstitutionScore::getConstitutionId, QuestionConstitutionScore::getTotalScore));

        // 动态规则匹配
//        AnswerResultVO result = determineResultByRules(scoreById, constitutionMap, dto.getSurveyId());
        AnswerResultVO result = determineResult(scores,sheetId);

        // 5.1 更新答卷结果
        sheet.setResultType(result.getResultType());
        sheet.setResultText(result.getResultText());
        this.updateById(sheet);
        // 更新答卷、返回结果
        return result;
    }

    /**
     * 获取问卷完整信息（带缓存）
     * @return 问卷VO
     */
    @Override
//    @Cacheable(value = "questionnaire",  unless = "#result == null")
    public QuestionnaireVO getQuestionnaire() {
        // 1. 查询问卷基本信息
//        QuestionSurvey survey = surveyMapper.selectById(surveyId);
        QuestionSurvey survey =  surveyMapper.selectOne(new QueryWrapper<QuestionSurvey>()
                .eq("status", 1)
                .orderByDesc("create_time")
                .last("LIMIT 1")
        );
        if (survey == null) {
            return null;
        }
        Long surveyId=survey.getId();
        // 2. 查询该问卷下的所有体质类型（按sort_order排序）
        List<QuestionConstitutionType> constitutions = constitutionTypeMapper.selectList(
                new LambdaQueryWrapper<QuestionConstitutionType>()
                        .eq(QuestionConstitutionType::getSurveyId, surveyId)
                        .orderByAsc(QuestionConstitutionType::getSortOrder)
        );
        if (CollUtil.isEmpty(constitutions)) {
            QuestionnaireVO vo = new QuestionnaireVO();
            vo.setSurveyId(surveyId);
            vo.setTitle(survey.getTitle());
            vo.setDescription(survey.getDescription());
            vo.setConstitutions(Collections.emptyList());
            return vo;
        }

        // 3. 查询所有体质对应的题目（批量，避免N+1）
        List<Long> constitutionIds = constitutions.stream()
                .map(QuestionConstitutionType::getId)
                .collect(Collectors.toList());
        List<QuestionQuestion> allQuestions = questionMapper.selectList(
                new LambdaQueryWrapper<QuestionQuestion>()
                        .in(QuestionQuestion::getConstitutionId, constitutionIds)
                        .orderByAsc(QuestionQuestion::getConstitutionId, QuestionQuestion::getSerialNumber)
        );
        if (CollUtil.isEmpty(allQuestions)) {
            // 没有题目则返回空列表
            QuestionnaireVO vo = new QuestionnaireVO();
            vo.setSurveyId(surveyId);
            vo.setTitle(survey.getTitle());
            vo.setDescription(survey.getDescription());
            vo.setConstitutions(buildConstitutionVOs(constitutions, Collections.emptyList(), Collections.emptyList()));
            return vo;
        }

        // 4. 查询所有题目的选项（每道题固定3个选项，也可批量查）
        List<Long> questionIds = allQuestions.stream()
                .map(QuestionQuestion::getId)
                .collect(Collectors.toList());
        List<QuestionOption> allOptions = optionMapper.selectList(
                new LambdaQueryWrapper<QuestionOption>()
                        .in(QuestionOption::getQuestionId, questionIds)
                        .orderByAsc(QuestionOption::getQuestionId, QuestionOption::getSortOrder)
        );

        // 5. 构建 Map 结构便于组装
        Map<Long, List<QuestionQuestion>> questionsByConstitutionId = allQuestions.stream()
                .collect(Collectors.groupingBy(QuestionQuestion::getConstitutionId));
        Map<Long, List<QuestionOption>> optionsByQuestionId = allOptions.stream()
                .collect(Collectors.groupingBy(QuestionOption::getQuestionId));

        // 6. 组装 VO
        List<QuestionnaireVO.ConstitutionVO> constitutionVOs = constitutions.stream().map(ct -> {
            QuestionnaireVO.ConstitutionVO ctVO = new QuestionnaireVO.ConstitutionVO();
            ctVO.setConstitutionId(ct.getId());
            ctVO.setName(ct.getName());
            ctVO.setAlias(ct.getAlias());
            ctVO.setDescription(ct.getDescription());
            ctVO.setSortOrder(ct.getSortOrder());

            List<QuestionQuestion> questions = questionsByConstitutionId.getOrDefault(ct.getId(), Collections.emptyList());
            List<QuestionnaireVO.QuestionVO> questionVOs = questions.stream().map(q -> {
                QuestionnaireVO.QuestionVO qVO = new QuestionnaireVO.QuestionVO();
                qVO.setQuestionId(q.getId());
                qVO.setSerialNumber(q.getSerialNumber());
                qVO.setContent(q.getContent());
                qVO.setFullScore(q.getFullScore());

                List<QuestionOption> options = optionsByQuestionId.getOrDefault(q.getId(),Collections.emptyList());
                List<QuestionnaireVO.OptionVO> optionVOs = options.stream().map(opt -> {
                    QuestionnaireVO.OptionVO optVO = new QuestionnaireVO.OptionVO();
                    optVO.setOptionId(opt.getId());
                    optVO.setOptionText(opt.getOptionText());
                    optVO.setScore(opt.getScore());
                    optVO.setSortOrder(opt.getSortOrder());
                    return optVO;
                }).collect(Collectors.toList());
                qVO.setOptions(optionVOs);
                return qVO;
            }).collect(Collectors.toList());
            ctVO.setQuestions(questionVOs);
            return ctVO;
        }).collect(Collectors.toList());

        QuestionnaireVO vo = new QuestionnaireVO();
        vo.setSurveyId(surveyId);
        vo.setTitle(survey.getTitle());
        vo.setDescription(survey.getDescription());
        vo.setConstitutions(constitutionVOs);
        return vo;
    }

    @Override
    public AnswerResultVO getResultBySheetId() {
        QuestionAnswerSheet sheet = this.getOne(new QueryWrapper<QuestionAnswerSheet>()
                .eq("app_user_id",SecurityUtils.getAppLoginUser().getAppUserId() )
                .orderByDesc("submit_time")
                .last("LIMIT 1")
        );
        if (sheet == null) {
            throw new RuntimeException("答卷不存在");
        }
        Long sheetId=sheet.getId();
        List<QuestionConstitutionScore> scores = constitutionScoreMapper.selectList(
                new LambdaQueryWrapper<QuestionConstitutionScore>().eq(QuestionConstitutionScore::getSheetId, sheetId));
        List<QuestionConstitutionType> constitutions = constitutionTypeMapper.selectList(null);
        Map<Long, QuestionConstitutionType> constitutionMap = constitutions.stream()
                .collect(Collectors.toMap(QuestionConstitutionType::getId, c -> c));
        AnswerResultVO vo = new AnswerResultVO();
        vo.setResultType(sheet.getResultType());
        vo.setResultText(sheet.getResultText());
        List<ConstitutionScoreDTO> dtoList = scores.stream().map(score -> {
            QuestionConstitutionType ct = constitutionMap.get(score.getConstitutionId());
            ConstitutionScoreDTO dto = new ConstitutionScoreDTO();
            dto.setConstitutionAlias(ct.getAlias());
            dto.setConstitutionName(ct.getName());
            dto.setTotalScore(score.getTotalScore());
            return dto;
        }).collect(Collectors.toList());
        vo.setConstitutionScores(dtoList);
        return vo;
    }
    /**
     * 计算答卷中各体质的得分
     */
    private List<QuestionConstitutionScore> computeConstitutionScores(Long sheetId) {
        // 查询该答卷的所有答案
        List<QuestionAnswerDetail> details =answerDetailMapper.getBySheetId(sheetId);
        if (CollUtil.isEmpty(details)) {
            return Collections.emptyList();
        }
        // 构建题目->选项分值的映射
        Map<Long, Integer> optionScoreMap = details.stream()
                .collect(Collectors.toMap(QuestionAnswerDetail::getQuestionId,
                        d -> d.getScore()));

        // 按体质分组计算总分
        Map<Long, Integer> constitutionScoreMap = new HashMap<>();
        for (QuestionAnswerDetail detail : details) {
            Long questionId = detail.getQuestionId();
            QuestionQuestion question = questionMapper.selectById(questionId);
            Long constitutionId = question.getConstitutionId();
            Integer score = optionScoreMap.getOrDefault(questionId, 0);
            constitutionScoreMap.merge(constitutionId, score, Integer::sum);
        }

        // 转为实体列表
        return constitutionScoreMap.entrySet().stream()
                .map(entry -> {
                    QuestionConstitutionScore score = new QuestionConstitutionScore();
                    score.setSheetId(sheetId);
                    score.setConstitutionId(entry.getKey());
                    score.setTotalScore(entry.getValue());
                    return score;
                }).collect(Collectors.toList());
    }

    /**
     * 根据得分规则判定体质结果
     */
    private AnswerResultVO determineResult(List<QuestionConstitutionScore> scores, Long sheetId) {
        // 获取所有体质信息（含 alias, name, isBalanced）
        List<QuestionConstitutionType> constitutions = constitutionTypeMapper.selectList(null);
        Map<Long, QuestionConstitutionType> constitutionMap = constitutions.stream()
                .collect(Collectors.toMap(QuestionConstitutionType::getId, c -> c));

        // 构建体质别名 -> 总分
        Map<String, Integer> scoreMap = new HashMap<>();
        for (QuestionConstitutionScore score : scores) {
            QuestionConstitutionType ct = constitutionMap.get(score.getConstitutionId());
            if (ct != null) {
                scoreMap.put(ct.getAlias(), score.getTotalScore());
            }
        }

        Integer pingheScore = scoreMap.getOrDefault("pinghe", 0);
        // 偏颇体质（排除平和）
        Map<String, Integer> biasedScores = new HashMap<>(scoreMap);
        biasedScores.remove("pinghe");

        // 规则1: 平和体质（总分≥8 且所有偏颇<6）
        boolean isPurePinghe = pingheScore >= 8 && biasedScores.values().stream().allMatch(v -> v < 6);
        if (isPurePinghe) {
            return buildResult("pinghe", "恭喜您，您的体质为“平和体质”，非常完美。请联系您的馆主或教练，领取训练及生活方案，继续保持哦。", scores, constitutionMap);
        }

        // 规则2: 某偏颇体质总分 ≥ 8
        Optional<String> highKey = biasedScores.entrySet().stream()
                .filter(e -> e.getValue() >= 8) .max(Map.Entry.comparingByValue()).map(Map.Entry::getKey);

        if (highKey.isPresent()) {
            String alias = highKey.get();
            String name = constitutionMap.values().stream()
                    .filter(ct -> ct.getAlias().equals(alias)).findFirst().get().getName();
            String text = String.format("亲爱的伽人您好，您的体质为典型%s。请联系您的馆主或教练，领取训练及生活方案，快速调整哦。", name);
            return buildResult(alias, text, scores, constitutionMap);
        }

        // 规则4: 两种及以上偏颇体质分数 ≥ 7
        List<String> keys = biasedScores.entrySet().stream()
                .filter(e -> e.getValue() >= 7) .map(Map.Entry::getKey).collect(Collectors.toList());
//        long count = biasedScores.values().stream().filter(v -> v >= 7).count();
        if (keys.size() >= 1) {
            String nameStr=constitutionMap.values().stream()
                    .filter(ct -> keys.contains(ct.getAlias()))
                    .map(QuestionConstitutionType::getName)
                    .collect(Collectors.joining(","));
            String isGrOne=keys.size()==1?nameStr:String.format("复合型体质(%s)",nameStr);
            String text = String.format("亲爱的伽人您好，您的体质为%s，建议综合调理。请联系您的馆主或教练，领取训练及生活方案，快速调整哦。", isGrOne);
            return buildResult("multiple", text, scores, constitutionMap);
        }

        // 规则3: 某偏颇体质总分在 6~7 之间
        Optional<String> midKey = biasedScores.entrySet().stream()
                .filter(e -> e.getValue() >= 6 && e.getValue() <= 7) .map(Map.Entry::getKey).findFirst();

        if (midKey.isPresent()) {
            String alias = midKey.get();
            String name = constitutionMap.values().stream()
                    .filter(ct -> ct.getAlias().equals(alias)).findFirst().get().getName().substring(0,2);
            String text = String.format("亲爱的伽人您好，您的体质为%s倾向体质。请联系您的馆主或教练，领取训练及生活方案，快速调整哦。", name);
            return buildResult(alias + "_tendency", text, scores, constitutionMap);
        }

        // 默认兜底（一般不会触发）
        return buildResult("unknown", "无法判定体质类型，请重新测评。", scores, constitutionMap);
    }


    // 修改 determineResult 方法，使用数据库规则动态判定

    /**
     *
     * @param scoreById 体质得分映射（体质ID -> 总分）
     * @param constitutionMap 模块信息
     * @param surveyId 问卷id
     * @return
     */
    private AnswerResultVO determineResultByRules(Map<Long, Integer> scoreById,
                                                  Map<Long, QuestionConstitutionType> constitutionMap,
                                                  Long surveyId) {
        List<QuestionRule> rules = ruleService.getEnabledRulesBySurveyId(surveyId);
        if (rules.isEmpty()) {
            return buildFallbackResult(scoreById, constitutionMap);
        }

        for (Long aLong : scoreById.keySet()) {

            Integer score = scoreById.get(aLong);
            if (score == null) continue;

            if (score >=8) {
                //
                scoreById.values().stream().filter(v -> v < 6).count();
            }

        }

        //

        // 预计算一些统计值，供规则使用
        Map<Long, Integer> biasedScores = new HashMap<>(scoreById);
//        Long pingheId = constitutionMap.values().stream()
//                .filter(ct -> ct.getIsBalanced() == 1)
//                .findFirst().map(QuestionConstitutionType::getId).orElse(null);
//        if (pingheId != null) {
//            biasedScores.remove(pingheId);
//        }
        int maxBiasedScore = biasedScores.values().stream().mapToInt(v -> v).max().orElse(0);
        long countBiasedGe7 = biasedScores.values().stream().filter(v -> v >= 7).count();

        // 按优先级匹配规则
//        for (QuestionRule rule : rules) {
//            boolean matched = false;
//            if ("constitution".equals(rule.getTargetType())) {
//                Long targetId = rule.getTargetConstitutionId();
//                if (targetId == null) continue;
//                Integer targetScore = scoreById.getOrDefault(targetId, 0);
//                // 检查目标体质得分区间
//                boolean scoreInRange = true;
//                if (rule.getMinScore() != null && targetScore < rule.getMinScore()) scoreInRange = false;
//                if (rule.getMaxScore() != null && targetScore > rule.getMaxScore()) scoreInRange = false;
//                if (!scoreInRange) continue;
//
//                // 检查“其他体质最高分上限”条件
//                boolean otherMaxOk = true;
//                if (rule.getRequireOtherMaxScore() != null) {
//                    // 若目标体质是平和体质，则其他体质包括所有偏颇；否则其他体质指除目标外的所有体质（含平和？按业务调整）
////                    if (pingheId != null && targetId.equals(pingheId)) {
////                        int maxOther = biasedScores.values().stream().mapToInt(v -> v).max().orElse(0);
////                        if (maxOther >= rule.getRequireOtherMaxScore()) otherMaxOk = false;
////                    } else {
//                        // 非平和体质：其他体质指除自己外所有（含平和）
//                        Map<Long, Integer> otherScores = new HashMap<>(scoreById);
//                        otherScores.remove(targetId);
//                        int maxOther = otherScores.values().stream().mapToInt(v -> v).max().orElse(0);
//                        if (maxOther >= rule.getRequireOtherMaxScore()) otherMaxOk = false;
////                    }
//                }
//                matched = scoreInRange && otherMaxOk;
//            }
//            else if ("compound".equals(rule.getTargetType())) {
//                // 复合型规则：例如 countBiasedGe7 >= 2，可存储在 condition_json 中
//                if (rule.getConditionJson() != null && !rule.getConditionJson().isEmpty()) {
//                    // 解析 JSON 条件，例如 {"countBiasedGe7": 2}
//                    // 简化：只支持 countBiasedGe7 比较
//                    // 实际可用 Jackson 解析
//                    matched = countBiasedGe7 >= 2; // 示例，可改为读取 JSON
//                }
//            }
//
//            if (matched) {
//                // 渲染结果文案：替换 ${targetName} 等变量
//                String targetName = "";
//                if (rule.getTargetConstitutionId() != null) {
//                    QuestionConstitutionType ct = constitutionMap.get(rule.getTargetConstitutionId());
//                    targetName = ct != null ? ct.getName() : "";
//                }
//                String resultText = rule.getResultText().replace("${targetName}", targetName);
//                // 确定结果类型：若目标体质存在则用其别名，否则用 rule 的 targetType
//                String resultType = "";
//                if (rule.getTargetConstitutionId() != null) {
//                    QuestionConstitutionType ct = constitutionMap.get(rule.getTargetConstitutionId());
//                    resultType = ct != null ? ct.getAlias() : rule.getTargetType();
//                } else {
//                    resultType = rule.getTargetType(); // "compound"
//                }
//                // 构建得分明细列表
//                List<ConstitutionScoreDTO> dtoList = scoreById.entrySet().stream()
//                        .map(e -> {
//                            QuestionConstitutionType ct = constitutionMap.get(e.getKey());
//                            ConstitutionScoreDTO dto = new ConstitutionScoreDTO();
//                            dto.setConstitutionAlias(ct.getAlias());
//                            dto.setConstitutionName(ct.getName());
//                            dto.setTotalScore(e.getValue());
//                            return dto;
//                        }).collect(Collectors.toList());
//                AnswerResultVO vo = new AnswerResultVO();
//                vo.setResultType(resultType);
//                vo.setResultText(resultText);
//                vo.setConstitutionScores(dtoList);
//                return vo;
//            }
//        }
        return buildFallbackResult(scoreById, constitutionMap);
    }

    private AnswerResultVO buildFallbackResult(Map<Long, Integer> scoreById,
                                               Map<Long, QuestionConstitutionType> constitutionMap) {
        // 兜底结果
        List<ConstitutionScoreDTO> dtoList = scoreById.entrySet().stream()
                .map(e -> {
                    QuestionConstitutionType ct = constitutionMap.get(e.getKey());
                    ConstitutionScoreDTO dto = new ConstitutionScoreDTO();
                    dto.setConstitutionAlias(ct.getAlias());
                    dto.setConstitutionName(ct.getName());
                    dto.setTotalScore(e.getValue());
                    return dto;
                }).collect(Collectors.toList());
        AnswerResultVO vo = new AnswerResultVO();
        vo.setResultType("unknown");
        vo.setResultText("无法判定体质类型，请重新测评。");
        vo.setConstitutionScores(dtoList);
        return vo;
    }

    // 简单表达式求值（示例，实际可用 Aviator/SpEL）
    private boolean evaluateCondition(String expression, int pingheScore, int maxBiasedScore, String alias, String name) {
        // 替换变量后使用 JavaScript 引擎或 SpEL
        // 例如：expression = "pingheScore >= 8 && maxBiasedScore < 6"
        // 实际实现请引入 AviatorEvaluator
        return false; // 伪代码
    }

    // 模板渲染（支持 ${name} 等变量）
    private String renderTemplate(String template, String name, int pingheScore) {
        return template.replace("${name}", name).replace("${pingheScore}", String.valueOf(pingheScore));
    }

    private AnswerResultVO buildResult(String resultType, String resultText,
                                       List<QuestionConstitutionScore> scores,
                                       Map<Long, QuestionConstitutionType> constitutionMap) {
        AnswerResultVO vo = new AnswerResultVO();
        vo.setResultType(resultType);
        vo.setResultText(resultText);

        List<ConstitutionScoreDTO> dtoList = scores.stream().map(score -> {
            QuestionConstitutionType ct = constitutionMap.get(score.getConstitutionId());
            ConstitutionScoreDTO dto = new ConstitutionScoreDTO();
            dto.setConstitutionAlias(ct.getAlias());
            dto.setConstitutionName(ct.getName());
            dto.setTotalScore(score.getTotalScore());
            return dto;
        }).collect(Collectors.toList());
        vo.setConstitutionScores(dtoList);
        return vo;
    }

    /**
     * 构建体质VO列表（包含题目和选项）
     * @param constitutions 体质类型列表
     * @param allQuestions 所有题目列表（可能为空）
     * @param allOptions 所有选项列表（可能为空）
     * @return 体质VO列表
     */
    private List<QuestionnaireVO.ConstitutionVO> buildConstitutionVOs(
            List<QuestionConstitutionType> constitutions,
            List<QuestionQuestion> allQuestions,
            List<QuestionOption> allOptions) {

        if (CollUtil.isEmpty(constitutions)) {
            return Collections.emptyList();
        }

        // 按体质ID分组题目
        Map<Long, List<QuestionQuestion>> questionsByConstitutionId = allQuestions.stream()
                .collect(Collectors.groupingBy(QuestionQuestion::getConstitutionId));

        // 按题目ID分组选项
        Map<Long, List<QuestionOption>> optionsByQuestionId = allOptions.stream()
                .collect(Collectors.groupingBy(QuestionOption::getQuestionId));

        // 构建结果
        return constitutions.stream().map(ct -> {
            QuestionnaireVO.ConstitutionVO ctVO = new QuestionnaireVO.ConstitutionVO();
            ctVO.setConstitutionId(ct.getId());
            ctVO.setName(ct.getName());
            ctVO.setAlias(ct.getAlias());
            ctVO.setDescription(ct.getDescription());
            ctVO.setSortOrder(ct.getSortOrder());

            // 获取该体质下的题目
            List<QuestionQuestion> questions = questionsByConstitutionId.getOrDefault(ct.getId(), Collections.emptyList());
            List<QuestionnaireVO.QuestionVO> questionVOs = questions.stream().map(q -> {
                QuestionnaireVO.QuestionVO qVO = new QuestionnaireVO.QuestionVO();
                qVO.setQuestionId(q.getId());
                qVO.setSerialNumber(q.getSerialNumber());
                qVO.setContent(q.getContent());
                qVO.setFullScore(q.getFullScore());

                // 获取该题目下的选项
                List<QuestionOption> options = optionsByQuestionId.getOrDefault(q.getId(), Collections.emptyList());
                List<QuestionnaireVO.OptionVO> optionVOs = options.stream().map(opt -> {
                    QuestionnaireVO.OptionVO optVO = new QuestionnaireVO.OptionVO();
                    optVO.setOptionId(opt.getId());
                    optVO.setOptionText(opt.getOptionText());
                    optVO.setScore(opt.getScore());
                    optVO.setSortOrder(opt.getSortOrder());
                    return optVO;
                }).collect(Collectors.toList());
                qVO.setOptions(optionVOs);
                return qVO;
            }).collect(Collectors.toList());

            ctVO.setQuestions(questionVOs);
            return ctVO;
        }).collect(Collectors.toList());
    }
}
