
package top.tqx.demo_1.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import top.tqx.demo_1.config.AiApiConfig;
import top.tqx.demo_1.dto.*;
import top.tqx.demo_1.entity.CollectionFile;
import top.tqx.demo_1.entity.ExamPaper;
import top.tqx.demo_1.entity.ExamRecord;
import top.tqx.demo_1.entity.Question;
import top.tqx.demo_1.entity.UserAnswer;
import top.tqx.demo_1.mapper.ExamPaperMapper;
import top.tqx.demo_1.mapper.ExamRecordMapper;
import top.tqx.demo_1.mapper.QuestionMapper;
import top.tqx.demo_1.mapper.UserAnswerMapper;
import top.tqx.demo_1.mapper.CollectionFileMapper;
import top.tqx.demo_1.service.ExamService;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ExamServiceImpl implements ExamService {

    private final RestTemplate restTemplate = new RestTemplate();
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private AiApiConfig aiApiConfig;

    @Autowired
    private QuestionMapper questionMapper;
    
    @Autowired
    private ExamRecordMapper examRecordMapper;
    
    @Autowired
    private ExamPaperMapper examPaperMapper;
    
    @Autowired
    private UserAnswerMapper userAnswerMapper;

    @Autowired
    private CollectionFileMapper collectionFileMapper;

    @Override
    public ExamGenerateResponse generateQuestions(ExamGenerateRequest request) throws IOException {
        boolean useSmartApi = (request.getQuestionTypes() == null);
        String url = useSmartApi ?
                aiApiConfig.getFullUrl(aiApiConfig.getExam().getGenerateSmart()) :
                aiApiConfig.getFullUrl(aiApiConfig.getExam().getGenerate());

        log.info("开始生成题目");
        log.info("请求参数: requestId={}, fileId={}, filePath={}, questionTypes={}, difficulty={}",
                request.getRequestId(), request.getFileId(), request.getFilePath(),
                request.getQuestionTypes(), request.getDifficulty());
        log.info("使用API: {}", useSmartApi ? "智能生成" : "指定题型");
        log.info("请求URL: {}", url);

        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            String jsonResponse = postJsonRequest(url, objectMapper.writeValueAsString(request), 120000);
            log.info("RAG服务响应: {}", jsonResponse);

            ExamGenerateResponse response = parseExamGenerateResponse(jsonResponse);
            log.info("RAG服务题目生成完成: success={}, questions count={}",
                    response.getSuccess(), response.getQuestions() != null ? response.getQuestions().size() : 0);

            if (Boolean.TRUE.equals(response.getSuccess()) && response.getQuestions() != null && !response.getQuestions().isEmpty()) {
                log.info("开始保存 {} 道题目到数据库", response.getQuestions().size());
                int savedCount = saveQuestionsToDatabase(response.getQuestions(), request.getFileId(), request.getCollectionName(), response.getSourceChunksUsed());
                log.info("成功保存 {} 道题目到数据库", savedCount);
            } else {
                log.warn("未生成任何题目，无需保存");
            }

            return response;

        } catch (Exception e) {
            log.error("生成题目失败: {}", e.getMessage(), e);
            throw new IOException("生成题目失败: " + e.getMessage(), e);
        }
    }

    @Override
    public Map<String, Object> generateQuestionsWithFileId(ExamGenerateRequest request) {
        log.info("generateQuestionsWithFileId 开始");
        log.info("请求参数: fileId={}, filePath={}, questionTypes={}",
                request.getFileId(), request.getFilePath(), request.getQuestionTypes());

        Map<String, Object> result = new HashMap<>();

        try {
            String collectionName = "test1";
            String filePath = "test1/1.docx";
            String documentName = "1.docx";

            if (request.getFileId() != null) {
                log.info("根据 fileId 查询 collection_file 表: fileId={}", request.getFileId());
                
                // 真正从数据库查询 collection_file 表
                List<CollectionFile> collectionFiles = collectionFileMapper.selectList(
                        new LambdaQueryWrapper<CollectionFile>()
                                .eq(CollectionFile::getFileId, request.getFileId())
                                .eq(CollectionFile::getStatus, 1));
                
                if (!collectionFiles.isEmpty()) {
                    CollectionFile cf = collectionFiles.get(0);
                    collectionName = cf.getCollectionName();
                    // 外部API需要的是向量库路径格式: collection_name/doc_name
                    // 而不是数据库中存储的服务器路径
                    filePath = collectionName + "/" + cf.getDocName();
                    documentName = cf.getDocName();
                    log.info("查询到文件信息: collectionName={}, filePath={}, documentName={}", 
                            collectionName, filePath, documentName);
                } else {
                    log.warn("未在 collection_file 表中找到 fileId={} 的记录，使用默认值", request.getFileId());
                }
                
                // 如果 request 中已经提供了，优先使用 request 中的值
                if (request.getCollectionName() != null) {
                    collectionName = request.getCollectionName();
                }
                if (request.getFilePath() != null) {
                    filePath = request.getFilePath();
                    documentName = request.getFilePath();
                }
                
                // 更新 request 对象，供后续调用使用
                request.setCollection(collectionName);
                request.setFilePath(filePath);
            } else if (request.getFilePath() != null) {
                log.info("直接使用 filePath: {}", request.getFilePath());
                filePath = request.getFilePath();
                if (request.getCollectionName() != null) {
                    collectionName = request.getCollectionName();
                }
                documentName = filePath;
                
                // 更新 request 对象，供后续调用使用
                request.setCollection(collectionName);
            } else {
                result.put("success", false);
                result.put("message", "file_id 或 file_path 不能同时为空");
                return result;
            }

            result.put("requestId", request.getRequestId());
            result.put("fileId", request.getFileId());
            result.put("fileMatchStatus", "success");
            result.put("matchedCollection", collectionName);
            result.put("matchedFilePath", filePath);
            result.put("matchedDocumentName", documentName);

            boolean useSmartApi = (request.getQuestionTypes() == null);
            String apiPath = useSmartApi ?
                    aiApiConfig.getExam().getGenerateSmart() :
                    aiApiConfig.getExam().getGenerate();

            log.info("使用API: {}, API路径: {}", useSmartApi ? "智能生成" : "指定题型", apiPath);

            Map<String, Object> generateParams = new HashMap<>();
            generateParams.put("file_path", filePath);
            generateParams.put("difficulty", request.getDifficulty());

            if (request.getQuestionTypes() != null) {
                generateParams.put("question_types", request.getQuestionTypes());
            }

            result.put("aiRequestParams", generateParams);
            result.put("aiApiPath", apiPath);
            result.put("success", true);
            result.put("message", "参数准备完成，等待异步处理");

            return result;

        } catch (Exception e) {
            log.error("generateQuestionsWithFileId 异常: {}", e.getMessage(), e);
            result.put("success", false);
            result.put("message", "处理失败: " + e.getMessage());
            return result;
        }
    }

    @Override
    public ExamGradeResponse gradeAnswers(ExamGradeRequest request) throws IOException {
        return gradeAnswers(request, null, null, null, null);
    }

    @Override
    public ExamGradeResponse gradeAnswers(ExamGradeRequest request, Long userId, String paperId) throws IOException {
        return gradeAnswers(request, userId, paperId, null, null);
    }

    @Override
    public ExamGradeResponse gradeAnswers(ExamGradeRequest request, Long userId, String paperId,
                                          String sessionId, String answerType) throws IOException {
        String url = aiApiConfig.getFullUrl(aiApiConfig.getExam().getGrade());

        log.info("Service层：开始批改题目");
        log.info("Service层参数详情:");
        log.info("  - userId: {}", userId);
        log.info("  - paperId: {}", paperId);
        log.info("  - sessionId: {}", sessionId);
        log.info("  - answerType: {}", answerType);
        log.info("  - 答案数量: {}", request.getAnswers() != null ? request.getAnswers().size() : 0);
        log.info("  - AI服务地址: {}", url);

        // 检查是否为空试卷
        boolean isBlankSubmission = request.getAnswers() == null || request.getAnswers().isEmpty();
        if (!isBlankSubmission) {
            isBlankSubmission = request.getAnswers().stream().allMatch(item -> 
                item.getStudentAnswer() == null || 
                (item.getStudentAnswer() instanceof String && ((String) item.getStudentAnswer()).trim().isEmpty()) ||
                (item.getStudentAnswer() instanceof List && ((List<?>) item.getStudentAnswer()).isEmpty())
            );
        }
        
        if (isBlankSubmission) {
            log.info("检测到空白试卷，跳过AI批改，直接返回0分");
            ExamGradeResponse response = new ExamGradeResponse();
            response.setSuccess(true);
            response.setTotalScore(BigDecimal.ZERO);
            response.setTotalMaxScore(BigDecimal.ZERO);
            response.setScoreRate(BigDecimal.ZERO);
            response.setResults(new ArrayList<>());
            return response;
        }

        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            log.info("Service层：准备发送请求到AI服务");
            log.info("请求体内容: {}", objectMapper.writeValueAsString(request));
            log.info("请求超时时间: 60000ms (60秒)");

            try {
                String jsonResponse = postJsonRequest(url, objectMapper.writeValueAsString(request), 60000);
                log.info("Service层：收到AI服务响应");
                log.info("响应原始内容: {}", jsonResponse);

                if (jsonResponse == null || jsonResponse.trim().isEmpty()) {
                    log.error("AI服务返回空响应");
                    throw new RuntimeException("AI服务返回空响应");
                }

                // 1. 先解析响应（不处理 feedback）
                com.fasterxml.jackson.databind.JsonNode rootNode = objectMapper.readTree(jsonResponse);
                com.fasterxml.jackson.databind.JsonNode dataNode = rootNode.has("data") ? rootNode.get("data") : rootNode;
                
                ExamGradeResponse response = parseExamGradeResponseBasic(dataNode);
                
                // 2. 从原始请求中补全 question_type 信息（AI响应中不包含此字段）
                if (response.getResults() != null && request.getAnswers() != null) {
                    for (int i = 0; i < response.getResults().size() && i < request.getAnswers().size(); i++) {
                        ExamGradeResponse.GradeResult result = response.getResults().get(i);
                        ExamGradeRequest.AnswerItem answerItem = request.getAnswers().get(i);
                        
                        if (result.getQuestionType() == null && answerItem.getQuestionType() != null) {
                            result.setQuestionType(answerItem.getQuestionType());
                            log.info("从请求中补全 question_type: {}", answerItem.getQuestionType());
                        }
                    }
                }
                
                // 3. 最后处理 feedback（此时 question_type 已经补全）
                processGradeResults(response, dataNode);
                
                log.info("Service层：AI服务批改完成");
                log.info("批改结果: success={}, totalScore={}, totalMaxScore={}, scoreRate={}",
                        response.getSuccess(),
                        response.getTotalScore(),
                        response.getTotalMaxScore(),
                        response.getScoreRate());

                if (response.getResults() != null) {
                    log.info("各题目批改结果:");
                    for (int i = 0; i < response.getResults().size(); i++) {
                        ExamGradeResponse.GradeResult result = response.getResults().get(i);
                        Boolean correctFlag = result.getCorrect() != null ? result.getCorrect() : result.getIsCorrect();
                        log.info("  题目{}({}): correct={}, score={}/{}, feedback={}",
                                i + 1,
                                result.getQuestionId(),
                                correctFlag,
                                result.getScore(),
                                result.getMaxScore(),
                                result.getFeedback());
                    }
                }

                return response;

            } catch (Exception e) {
                log.error("Service层：调用AI服务失败");
                log.error("错误类型: {}", e.getClass().getName());
                log.error("错误信息: {}", e.getMessage());
                log.error("错误详情:");

                if (e instanceof java.net.SocketTimeoutException) {
                    log.error("  可能原因: AI服务连接超时");
                    log.error("  建议: 检查AI服务是否正常运行，或增加超时时间");
                } else if (e instanceof java.net.ConnectException) {
                    log.error("  可能原因: 无法连接到AI服务");
                    log.error("  建议: 检查AI服务地址和端口是否正确");
                } else if (e instanceof com.fasterxml.jackson.core.JsonProcessingException) {
                    log.error("  可能原因: AI服务响应格式错误");
                    log.error("  建议: 检查AI服务返回的JSON格式");
                }

                log.error("错误堆栈: ", e);
                throw new RuntimeException("调用AI服务失败: " + e.getMessage(), e);
            }

        } catch (Exception e) {
            log.error("Service层：批改题目发生未知异常");
            log.error("错误类型: {}", e.getClass().getName());
            log.error("错误信息: {}", e.getMessage());
            log.error("详细堆栈: ", e);
            throw new RuntimeException("Service层批改题目失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ExamRecordResponse gradeAnswersForRecord(String recordId, ExamSaveRequest request, Long userId, String answerType) {
        log.info("gradeAnswersForRecord 开始");
        log.info("请求参数: recordId={}, userId={}, answerType={}, answers count={}",
                recordId, userId, answerType, request.getAnswers() != null ? request.getAnswers().size() : 0);

        // 1. 查找考试记录
        ExamRecord examRecord = examRecordMapper.selectOne(
                new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getRecordId, recordId));

        if (examRecord == null) {
            log.error("找不到考试记录: recordId={}", recordId);
            throw new RuntimeException("考试记录不存在");
        }

        // 2. 查找试卷
        ExamPaper examPaper = examPaperMapper.selectOne(
                new LambdaQueryWrapper<ExamPaper>().eq(ExamPaper::getPaperId, examRecord.getPaperId()));

        if (examPaper == null) {
            log.error("找不到试卷: paperId={}", examRecord.getPaperId());
            throw new RuntimeException("试卷不存在");
        }

        // 3. 准备调用AI服务
        ExamGradeRequest gradeRequest = new ExamGradeRequest();
        gradeRequest.setRecordId(recordId);
        gradeRequest.setPaperId(examRecord.getPaperId());
        gradeRequest.setAnswerType(answerType);

        // 从试卷中加载题目详情
        List<ExamGradeRequest.AnswerItem> answerItems = new ArrayList<>();
        
        // 检查是否为空试卷
        boolean isBlankSubmission = request.getAnswers() == null || request.getAnswers().isEmpty();
        
        if (!isBlankSubmission) {
            // 检查是否所有答案都为空
            isBlankSubmission = request.getAnswers().stream().allMatch(item -> 
                item.getAnswer() == null || 
                (item.getAnswer() instanceof String && ((String) item.getAnswer()).trim().isEmpty()) ||
                (item.getAnswer() instanceof List && ((List<?>) item.getAnswer()).isEmpty())
            );
        }
        
        log.info("检测到空试卷提交: isBlankSubmission={}", isBlankSubmission);
        
        if (!isBlankSubmission) {
            for (ExamSaveRequest.AnswerItem saveItem : request.getAnswers()) {
                ExamGradeRequest.AnswerItem gradeItem = new ExamGradeRequest.AnswerItem();
                gradeItem.setQuestionId(saveItem.getQuestionId());
                gradeItem.setQuestionType(saveItem.getQuestionType());
                gradeItem.setStudentAnswer(saveItem.getAnswer());
                
                // 从题库加载题目内容
                Question question = questionMapper.selectOne(
                        new LambdaQueryWrapper<Question>().eq(Question::getQuestionId, saveItem.getQuestionId()));
                
                // 设置题目内容（确保不为null）
                if (question != null && question.getContent() != null) {
                    try {
                        ExamGradeRequest.QuestionContent questionContent = objectMapper.treeToValue(
                                question.getContent(), ExamGradeRequest.QuestionContent.class);
                        gradeItem.setQuestionContent(questionContent);
                    } catch (Exception e) {
                        log.warn("转换题目内容失败", e);
                    }
                }
                
                // 设置满分（确保不为null）
                if (question != null && question.getScore() != null) {
                    gradeItem.setMaxScore(question.getScore());
                } else {
                    gradeItem.setMaxScore(new BigDecimal(5));
                }
                
                // 确保questionContent不为null，避免AI服务报错
                if (gradeItem.getQuestionContent() == null) {
                    ExamGradeRequest.QuestionContent questionContent = new ExamGradeRequest.QuestionContent();
                    questionContent.setStem("");
                    questionContent.setAnswer("");
                    gradeItem.setQuestionContent(questionContent);
                    log.warn("题目内容为空，已设置默认值: questionId={}", saveItem.getQuestionId());
                }
                
                answerItems.add(gradeItem);
            }
        } else {
            // 空答案提交时，也要复制基础信息到gradeRequest，确保后续保存时长度一致
            for (ExamSaveRequest.AnswerItem saveItem : request.getAnswers()) {
                ExamGradeRequest.AnswerItem gradeItem = new ExamGradeRequest.AnswerItem();
                gradeItem.setQuestionId(saveItem.getQuestionId());
                gradeItem.setQuestionType(saveItem.getQuestionType());
                gradeItem.setStudentAnswer(saveItem.getAnswer());
                answerItems.add(gradeItem);
            }
        }
        gradeRequest.setAnswers(answerItems);

        // 4. 调用AI服务批改（空试卷直接返回0分，不调用AI）
        ExamGradeResponse gradeResponse;
        if (isBlankSubmission) {
            log.info("检测到空白试卷，跳过AI批改，直接返回0分");
            gradeResponse = createBlankGradeResponse(request.getAnswers());
        } else {
            try {
                gradeResponse = gradeAnswers(
                        gradeRequest, userId, examRecord.getPaperId(), null, answerType);
            } catch (IOException e) {
                log.error("调用AI服务失败: {}", e.getMessage(), e);
                throw new RuntimeException("AI服务调用失败: " + e.getMessage(), e);
            }
        }

        if (!Boolean.TRUE.equals(gradeResponse.getSuccess())) {
            log.error("AI批改失败: {}", gradeResponse.getError());
            throw new RuntimeException("AI批改失败: " + gradeResponse.getError());
        }

        // 5. 更新考试记录
        examRecord.setStatus("graded");
        examRecord.setTotalScore(gradeResponse.getTotalScore());
        examRecord.setSubmitTime(LocalDateTime.now());
        examRecord.setGradedTime(LocalDateTime.now());
        
        // 计算答题耗时
        examRecord.setTimeSpent(calculateTimeSpent(examRecord));
        
        examRecord.setUpdatedAt(LocalDateTime.now());
        examRecordMapper.updateById(examRecord);

        // 6. 保存答题记录
        saveUserAnswersForExam(gradeRequest, gradeResponse, userId, examRecord);

        // 7. 准备返回结果
        ExamRecordResponse response = new ExamRecordResponse();
        response.setRecordId(recordId);
        response.setPaperId(examRecord.getPaperId());
        response.setUserId(userId);
        response.setStatus("graded");
        response.setTotalScore(gradeResponse.getTotalScore());
        response.setPaperTitle(examPaper.getTitle());
        response.setAnswerType(answerType);

        // 获取答题详情
        response.setAnswers(getAnswerDetails(gradeResponse));

        log.info("gradeAnswersForRecord 完成，总分: {}", gradeResponse.getTotalScore());

        return response;
    }

    /**
     * 计算考试耗时
     */
    private Integer calculateTimeSpent(ExamRecord examRecord) {
        if (examRecord.getStartTime() != null) {
            Duration duration = Duration.between(examRecord.getStartTime(), LocalDateTime.now());
            return (int) duration.toSeconds();
        }
        return null;
    }

    /**
     * 保存正式考试的答题记录
     */
    private void saveUserAnswersForExam(ExamGradeRequest request, ExamGradeResponse response, Long userId, ExamRecord examRecord) {
        ObjectMapper objectMapper = new ObjectMapper();
        List<ExamGradeResponse.GradeResult> results = response.getResults();
        
        if (results == null) return;
        
        for (int i = 0; i < results.size(); i++) {
            ExamGradeResponse.GradeResult result = results.get(i);
            ExamGradeRequest.AnswerItem answerItem = request.getAnswers().get(i);
            
            UserAnswer userAnswer = new UserAnswer();
            userAnswer.setUserId(userId);
            userAnswer.setQuestionId(result.getQuestionId());
            userAnswer.setQuestionType(answerItem.getQuestionType());
            userAnswer.setAnswerType(examRecord.getAnswerType());
            userAnswer.setPaperId(examRecord.getPaperId());
            userAnswer.setScore(result.getScore());
            userAnswer.setMaxScore(result.getMaxScore());
            
            try {
                JsonNode answerNode = objectMapper.valueToTree(answerItem.getStudentAnswer());
                userAnswer.setUserAnswer(answerNode);
            } catch (Exception e) {
                log.warn("转换学生答案失败", e);
            }
            
            Boolean isCorrect = result.getCorrect() != null ? result.getCorrect() : result.getIsCorrect();
            
            // 判断答题状态：0=错误，1=正确，2=半对
            Integer correctStatus;
            if (Boolean.TRUE.equals(isCorrect)) {
                correctStatus = 1;  // 完全正确
            } else {
                // 检查是否为半对（得分>0但<满分，适用于主观题）
                BigDecimal score = result.getScore();
                BigDecimal maxScore = result.getMaxScore();
                if (score != null && maxScore != null && 
                    score.compareTo(BigDecimal.ZERO) > 0 && 
                    score.compareTo(maxScore) < 0) {
                    correctStatus = 2;  // 半对
                } else {
                    correctStatus = 0;  // 错误
                }
            }
            userAnswer.setIsCorrect(correctStatus);
            userAnswer.setGradingType("ai");
            userAnswer.setFeedback(result.getFeedback());
            userAnswer.setCreatedAt(LocalDateTime.now());
            userAnswer.setUpdatedAt(LocalDateTime.now());
            
            try {
                userAnswerMapper.insert(userAnswer);
            } catch (org.springframework.dao.DuplicateKeyException e) {
                log.warn("检测到重复提交: userId={}, questionId={}, paperId={}", 
                        userId, result.getQuestionId(), examRecord.getPaperId());
                throw new RuntimeException("不允许重复做题：您已完成此题的作答，请勿重复提交");
            }
        }
        
        log.info("保存了{}条考试答题记录", results.size());
    }

    /**
     * 构建答题详情列表
     */
    private List<ExamRecordResponse.AnswerDetail> getAnswerDetails(ExamGradeResponse response) {
        List<ExamRecordResponse.AnswerDetail> details = new ArrayList<>();
        
        if (response.getResults() == null) return details;
        
        for (ExamGradeResponse.GradeResult result : response.getResults()) {
            ExamRecordResponse.AnswerDetail detail = new ExamRecordResponse.AnswerDetail();
            detail.setQuestionId(result.getQuestionId());
            detail.setScore(result.getScore());
            Boolean isCorrect = result.getCorrect() != null ? result.getCorrect() : result.getIsCorrect();
            detail.setIsCorrect(isCorrect);
            detail.setFeedback(result.getFeedback());
            details.add(detail);
        }
        
        return details;
    }

    @Override
    public ExamPaperGenerateResponse generatePaper(ExamPaperGenerateRequest request, Long userId, Long deptId, Integer userType) {
        ExamPaperGenerateResponse response = new ExamPaperGenerateResponse();
        response.setPaperId(UUID.randomUUID().toString());
        response.setPaperTitle("自动生成的试卷");
        response.setGeneratedAt(java.time.LocalDateTime.now());
        response.setPermissionScope("department");

        List<ExamPaperGenerateResponse.ExamPaperQuestion> allQuestions = new ArrayList<>();
        BigDecimal totalScore = BigDecimal.ZERO;
        Map<String, String> warnings = new HashMap<>();

        if (request.getSingleChoiceCount() != null && request.getSingleChoiceCount() > 0) {
            QuestionSelectionResult result = selectQuestionsByType(
                    "single_choice",
                    request.getSingleChoiceCount(),
                    deptId,
                    Boolean.TRUE.equals(request.getIncludePersonal()),
                    request.getDifficulty(),
                    request.getFileIds(),
                    userType
            );
            allQuestions.addAll(result.getQuestions());
            if (result.hasWarning) {
                warnings.put("single_choice", result.warning);
            }
        }

        if (request.getMultipleChoiceCount() != null && request.getMultipleChoiceCount() > 0) {
            QuestionSelectionResult result = selectQuestionsByType(
                    "multiple_choice",
                    request.getMultipleChoiceCount(),
                    deptId,
                    Boolean.TRUE.equals(request.getIncludePersonal()),
                    request.getDifficulty(),
                    request.getFileIds(),
                    userType
            );
            allQuestions.addAll(result.getQuestions());
            if (result.hasWarning) {
                warnings.put("multiple_choice", result.warning);
            }
        }

        if (request.getTrueFalseCount() != null && request.getTrueFalseCount() > 0) {
            QuestionSelectionResult result = selectQuestionsByType(
                    "true_false",
                    request.getTrueFalseCount(),
                    deptId,
                    Boolean.TRUE.equals(request.getIncludePersonal()),
                    request.getDifficulty(),
                    request.getFileIds(),
                    userType
            );
            allQuestions.addAll(result.getQuestions());
            if (result.hasWarning) {
                warnings.put("true_false", result.warning);
            }
        }

        if (request.getFillBlankCount() != null && request.getFillBlankCount() > 0) {
            QuestionSelectionResult result = selectQuestionsByType(
                    "fill_blank",
                    request.getFillBlankCount(),
                    deptId,
                    Boolean.TRUE.equals(request.getIncludePersonal()),
                    request.getDifficulty(),
                    request.getFileIds(),
                    userType
            );
            allQuestions.addAll(result.getQuestions());
            if (result.hasWarning) {
                warnings.put("fill_blank", result.warning);
            }
        }

        if (request.getSubjectiveCount() != null && request.getSubjectiveCount() > 0) {
            QuestionSelectionResult result = selectQuestionsByType(
                    "subjective",
                    request.getSubjectiveCount(),
                    deptId,
                    Boolean.TRUE.equals(request.getIncludePersonal()),
                    request.getDifficulty(),
                    request.getFileIds(),
                    userType
            );
            allQuestions.addAll(result.getQuestions());
            if (result.hasWarning) {
                warnings.put("subjective", result.warning);
            }
        }

        for (ExamPaperGenerateResponse.ExamPaperQuestion q : allQuestions) {
            if (q.getScore() != null) {
                totalScore = totalScore.add(q.getScore());
            }
        }

        response.setQuestions(allQuestions);
        response.setTotalScore(totalScore);
        response.setQuestionCount(allQuestions.size());
        response.setWarnings(warnings.isEmpty() ? null : warnings);

        log.info("试卷生成完成: paperId={}, questionCount={}, totalScore={}",
                response.getPaperId(), response.getQuestionCount(), response.getTotalScore());

        return response;
    }

    private QuestionSelectionResult selectQuestionsByType(String type, int count, Long deptId, boolean includePersonal, Integer difficulty, List<Long> fileIds, Integer userType) {
        QuestionSelectionResult result = new QuestionSelectionResult();
        List<ExamPaperGenerateResponse.ExamPaperQuestion> selectedQuestions = new ArrayList<>();
        try {
            com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Question> queryWrapper =
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
            queryWrapper.eq(Question::getQuestionType, type);
            if (difficulty != null && difficulty > 0) {
                queryWrapper.eq(Question::getDifficulty, difficulty);
            }
            if (fileIds != null && !fileIds.isEmpty()) {
                List<String> validDocumentIds = fileIds.stream()
                        .filter(id -> id != null && id > 0)
                        .map(String::valueOf)
                        .collect(Collectors.toList());
                if (!validDocumentIds.isEmpty()) {
                    queryWrapper.in(Question::getDocumentId, validDocumentIds);
                }
            }
            queryWrapper.in(Question::getStatus, "active", "approved");
            long totalCount = questionMapper.selectCount(queryWrapper);
            if (totalCount < count) {
                log.warn("题库中{}类型的题目数量不足，需要{}道，实际只有{}道", type, count, totalCount);
                result.hasWarning = true;
                result.warning = String.format("%s类型题目数量不足，仅有%d道（需要%d道）", getQuestionTypeName(type), (int) totalCount, count);
                count = (int) Math.min(count, totalCount);
            }
            if (count > 0) {
                queryWrapper.last("ORDER BY RAND() LIMIT " + count);
                List<Question> questions = questionMapper.selectList(queryWrapper);
                for (Question question : questions) {
                    ExamPaperGenerateResponse.ExamPaperQuestion paperQuestion = new ExamPaperGenerateResponse.ExamPaperQuestion();
                    paperQuestion.setQuestionId(question.getQuestionId());
                    paperQuestion.setQuestionType(question.getQuestionType());
                    paperQuestion.setContent(question.getContent());
                    paperQuestion.setScore(question.getScore() != null ? question.getScore() : new BigDecimal(5));
                    paperQuestion.setDifficulty(question.getDifficulty());
                    paperQuestion.setDocumentName(question.getDocumentName());
                    paperQuestion.setKnowledgeBasePath(question.getKnowledgeBasePath());
                    selectedQuestions.add(paperQuestion);
                }
                log.info("成功选择{}道{}类型题目", selectedQuestions.size(), type);
            }
        } catch (Exception e) {
            log.error("选择{}类型题目失败: {}", type, e.getMessage(), e);
            result.hasWarning = true;
            result.warning = "选择" + getQuestionTypeName(type) + "题目时发生错误";
        }
        result.setQuestions(selectedQuestions);
        return result;
    }

    private String getQuestionTypeName(String type) {
        switch (type) {
            case "single_choice":
                return "单选题";
            case "multiple_choice":
                return "多选题";
            case "true_false":
                return "判断题";
            case "fill_blank":
                return "填空题";
            case "subjective":
                return "主观题";
            default:
                return type;
        }
    }

    private String postJsonRequest(String url, String jsonBody, int timeout) throws IOException {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity<String> entity = new HttpEntity<>(jsonBody, headers);

        try {
            ResponseEntity<String> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    entity,
                    String.class
            );

            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                return response.getBody();
            } else {
                throw new IOException("HTTP请求失败: " + response.getStatusCode());
            }
        } catch (Exception e) {
            log.error("POST请求失败: url={}, error={}", url, e.getMessage());
            throw new IOException("POST请求失败: " + e.getMessage(), e);
        }
    }

    private ExamGenerateResponse parseExamGenerateResponse(String jsonResponse) throws IOException {
        try {
            com.fasterxml.jackson.databind.JsonNode rootNode = objectMapper.readTree(jsonResponse);
            
            if (rootNode.has("data")) {
                return objectMapper.readValue(jsonResponse, ExamGenerateResponse.class);
            }
            
            return objectMapper.readValue(jsonResponse, ExamGenerateResponse.class);
        } catch (Exception e) {
            log.error("解析生成题目响应失败: {}", e.getMessage());
            throw new IOException("解析生成题目响应失败: " + e.getMessage(), e);
        }
    }

    private ExamGradeResponse parseExamGradeResponseBasic(com.fasterxml.jackson.databind.JsonNode dataNode) throws IOException {
        try {
            ExamGradeResponse response = new ExamGradeResponse();
            
            // 解析顶层字段
            if (dataNode.has("success")) {
                response.setSuccess(dataNode.get("success").asBoolean());
            }
            if (dataNode.has("request_id")) {
                response.setRequestId(dataNode.get("request_id").asText());
            }
            if (dataNode.has("paper_id")) {
                response.setPaperId(dataNode.get("paper_id").asText());
            }
            if (dataNode.has("total_score")) {
                response.setTotalScore(dataNode.get("total_score").decimalValue());
            }
            if (dataNode.has("total_max_score")) {
                response.setTotalMaxScore(dataNode.get("total_max_score").decimalValue());
            }
            if (dataNode.has("score_rate")) {
                response.setScoreRate(dataNode.get("score_rate").decimalValue());
            }
            
            // 解析 results 数组
            if (dataNode.has("results") && dataNode.get("results").isArray()) {
                com.fasterxml.jackson.databind.JsonNode resultsArray = dataNode.get("results");
                List<ExamGradeResponse.GradeResult> results = new ArrayList<>();
                
                log.info("开始解析 {} 道题", resultsArray.size());
                
                for (int i = 0; i < resultsArray.size(); i++) {
                    com.fasterxml.jackson.databind.JsonNode resultNode = resultsArray.get(i);
                    ExamGradeResponse.GradeResult result = new ExamGradeResponse.GradeResult();
                    
                    // 打印完整的 resultNode 结构
                    log.info("第 {} 题 resultNode 内容: {}", i + 1, resultNode.toString());
                    log.info("resultNode 字段: {}", java.util.stream.StreamSupport.stream(resultNode.spliterator(), false)
                            .map(n -> n.asText()).collect(java.util.stream.Collectors.joining(", ")));
                    
                    // 基本字段
                    if (resultNode.has("question_id")) {
                        result.setQuestionId(resultNode.get("question_id").asText());
                        log.info("读取到 question_id: {}", result.getQuestionId());
                    }
                    if (resultNode.has("question_type")) {
                        result.setQuestionType(resultNode.get("question_type").asText());
                        log.info("读取到 question_type: {}", result.getQuestionType());
                    }
                    if (resultNode.has("score")) {
                        result.setScore(resultNode.get("score").decimalValue());
                    }
                    if (resultNode.has("max_score")) {
                        result.setMaxScore(resultNode.get("max_score").decimalValue());
                    }
                    if (resultNode.has("correct")) {
                        result.setCorrect(resultNode.get("correct").asBoolean());
                    }
                    if (resultNode.has("is_correct")) {
                        result.setIsCorrect(resultNode.get("is_correct").asBoolean());
                    }
                    
                    results.add(result);
                }
                
                response.setResults(results);
            }
            
            return response;
        } catch (Exception e) {
            log.error("解析批改响应失败: {}", e.getMessage(), e);
            throw new IOException("解析批改响应失败: " + e.getMessage(), e);
        }
    }
    
    private void processGradeResults(ExamGradeResponse response, com.fasterxml.jackson.databind.JsonNode dataNode) {
        if (response.getResults() == null || response.getResults().isEmpty()) {
            return;
        }
        
        com.fasterxml.jackson.databind.JsonNode resultsArray = dataNode.get("results");
        
        for (int i = 0; i < response.getResults().size(); i++) {
            ExamGradeResponse.GradeResult result = response.getResults().get(i);
            com.fasterxml.jackson.databind.JsonNode resultNode = resultsArray.get(i);
            
            StringBuilder feedbackBuilder = new StringBuilder();
            
            String questionType = result.getQuestionType();
            log.info("处理第 {} 题, 类型: {}", i + 1, questionType);
            
            // 主观题处理
            if ("subjective".equals(questionType) && resultNode.has("details")) {
                log.info("检测到主观题，手动解析 details");
                com.fasterxml.jackson.databind.JsonNode detailsNode = resultNode.get("details");
                
                if (detailsNode.has("highlights")) {
                    feedbackBuilder.append("【亮点】\n");
                    com.fasterxml.jackson.databind.JsonNode highlightsNode = detailsNode.get("highlights");
                    if (highlightsNode.isArray()) {
                        for (int j = 0; j < highlightsNode.size(); j++) {
                            feedbackBuilder.append(j + 1).append(". ").append(highlightsNode.get(j).asText()).append("\n");
                        }
                    }
                }
                
                if (detailsNode.has("overall_feedback")) {
                    feedbackBuilder.append("【综合评价】\n").append(detailsNode.get("overall_feedback").asText()).append("\n");
                }
                
                if (detailsNode.has("scoring_breakdown")) {
                    feedbackBuilder.append("【评分详情】\n");
                    com.fasterxml.jackson.databind.JsonNode breakdownsNode = detailsNode.get("scoring_breakdown");
                    if (breakdownsNode.isArray()) {
                        for (int j = 0; j < breakdownsNode.size(); j++) {
                            com.fasterxml.jackson.databind.JsonNode breakdownNode = breakdownsNode.get(j);
                            String point = breakdownNode.has("point") ? breakdownNode.get("point").asText() : "";
                            double weight = breakdownNode.has("weight") ? breakdownNode.get("weight").asDouble() : 0;
                            double achieved = breakdownNode.has("achieved") ? breakdownNode.get("achieved").asDouble() : 0;
                            String comment = breakdownNode.has("comment") ? breakdownNode.get("comment").asText() : "";
                            
                            feedbackBuilder.append("- ").append(point)
                                    .append(" (权重: ").append((int)(weight * 100)).append("%, 得分率: ").append((int)(achieved * 100)).append("%)")
                                    .append("\n  评价: ").append(comment).append("\n");
                        }
                    }
                }
                
                if (detailsNode.has("shortcomings")) {
                    feedbackBuilder.append("【可改进之处】\n");
                    com.fasterxml.jackson.databind.JsonNode shortcomingsNode = detailsNode.get("shortcomings");
                    if (shortcomingsNode.isArray()) {
                        for (int j = 0; j < shortcomingsNode.size(); j++) {
                            feedbackBuilder.append(j + 1).append(". ").append(shortcomingsNode.get(j).asText()).append("\n");
                        }
                    }
                }
                
                if (feedbackBuilder.length() > 0) {
                    result.setFeedback(feedbackBuilder.toString().trim());
                    log.info("主观题 feedback 已设置，长度: {}", result.getFeedback().length());
                }
            } 
            // 填空题处理
            else if ("fill_blank".equals(questionType)) {
                log.info("检测到填空题");
                
                if (resultNode.has("feedback")) {
                    feedbackBuilder.append(resultNode.get("feedback").asText()).append("\n");
                }
                
                if (resultNode.has("correct_answers")) {
                    com.fasterxml.jackson.databind.JsonNode correctAnswersNode = resultNode.get("correct_answers");
                    if (correctAnswersNode.isArray()) {
                        feedbackBuilder.append("【正确答案】\n");
                        for (int j = 0; j < correctAnswersNode.size(); j++) {
                            feedbackBuilder.append("第").append(j + 1).append("空: ").append(correctAnswersNode.get(j).asText()).append("\n");
                        }
                    }
                }
                
                if (feedbackBuilder.length() > 0) {
                    result.setFeedback(feedbackBuilder.toString().trim());
                    log.info("填空题 feedback 已设置，长度: {}", result.getFeedback().length());
                }
            } 
            // 其他题型，直接用原始 feedback
            else if (resultNode.has("feedback")) {
                result.setFeedback(resultNode.get("feedback").asText());
            }
        }
    }

    private static class QuestionSelectionResult {
        private List<ExamPaperGenerateResponse.ExamPaperQuestion> questions;
        private boolean hasWarning;
        private String warning;

        public List<ExamPaperGenerateResponse.ExamPaperQuestion> getQuestions() {
            return questions;
        }

        public void setQuestions(List<ExamPaperGenerateResponse.ExamPaperQuestion> questions) {
            this.questions = questions;
        }
    }

    private int saveQuestionsToDatabase(List<ExamGenerateRequest.Question> questions, Long fileId, String collectionName, Integer sourceChunksUsed) {
        int savedCount = 0;
        for (ExamGenerateRequest.Question q : questions) {
            try {
                Question question = new Question();
                question.setQuestionId(UUID.randomUUID().toString());
                question.setQuestionType(q.getQuestionType());
                question.setDifficulty(q.getDifficulty() != null ? q.getDifficulty() : 3);
                question.setScore(q.getScore() != null ? q.getScore() : new BigDecimal("5.00"));
                question.setStatus("pending");
                question.setDocumentId(fileId != null ? fileId.toString() : null);
                question.setDocumentName(q.getContent() != null ? 
                        (q.getContent().getStem() != null ? 
                                (q.getContent().getStem().length() > 255 ? 
                                        q.getContent().getStem().substring(0, 255) : q.getContent().getStem()) : null) : null);
                question.setKnowledgeBasePath(collectionName);
                question.setSourceContext(null);
                question.setSourceChunksUsed(sourceChunksUsed != null ? sourceChunksUsed : 0);
                question.setExamCount(0);
                question.setCorrectCount(0);

                if (q.getContent() != null) {
                    question.setContent(toJsonNode(q.getContent()));
                }

                if (q.getSourceTrace() != null) {
                    question.setChunkIds(toJsonNode(q.getSourceTrace().getChunkIds()));
                }

                question.setCreatedAt(LocalDateTime.now());
                question.setUpdatedAt(LocalDateTime.now());

                questionMapper.insert(question);
                savedCount++;
                log.debug("保存题目成功: questionId={}, type={}", question.getQuestionId(), question.getQuestionType());
            } catch (Exception e) {
                log.error("保存题目失败: questionType={}, error={}", q.getQuestionType(), e.getMessage(), e);
            }
        }
        return savedCount;
    }

    private com.fasterxml.jackson.databind.JsonNode toJsonNode(Object obj) {
        try {
            if (obj == null) {
                return null;
            }
            return objectMapper.valueToTree(obj);
        } catch (Exception e) {
            log.warn("转换对象为JsonNode失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 创建空白试卷批改响应
     * 当检测到空答案时，直接返回0分，不调用AI服务
     */
    private ExamGradeResponse createBlankGradeResponse(List<ExamSaveRequest.AnswerItem> answers) {
        ExamGradeResponse response = new ExamGradeResponse();
        response.setSuccess(true);
        response.setTotalScore(BigDecimal.ZERO);
        response.setTotalMaxScore(BigDecimal.ZERO);
        response.setScoreRate(BigDecimal.ZERO);
        
        List<ExamGradeResponse.GradeResult> results = new ArrayList<>();
        
        if (answers != null && !answers.isEmpty()) {
            BigDecimal totalMaxScore = BigDecimal.ZERO;
            
            for (ExamSaveRequest.AnswerItem item : answers) {
                ExamGradeResponse.GradeResult result = new ExamGradeResponse.GradeResult();
                result.setQuestionId(item.getQuestionId());
                result.setQuestionType(item.getQuestionType());
                result.setScore(BigDecimal.ZERO);
                
                // 获取题目满分
                BigDecimal maxScore = new BigDecimal(5);
                if (item.getQuestionId() != null) {
                    Question question = questionMapper.selectOne(
                            new LambdaQueryWrapper<Question>().eq(Question::getQuestionId, item.getQuestionId()));
                    if (question != null && question.getScore() != null) {
                        maxScore = question.getScore();
                    }
                }
                result.setMaxScore(maxScore);
                totalMaxScore = totalMaxScore.add(maxScore);
                
                result.setCorrect(false);
                result.setIsCorrect(false);
                result.setFeedback("未作答");
                
                results.add(result);
            }
            
            response.setTotalMaxScore(totalMaxScore);
        }
        
        response.setResults(results);
        log.info("创建空白试卷响应: totalScore=0, totalMaxScore={}, questionCount={}", 
                response.getTotalMaxScore(), results.size());
        
        return response;
    }
}

