package top.tqx.demo_1.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import top.tqx.demo_1.common.Result;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import top.tqx.demo_1.dto.*;
import top.tqx.demo_1.entity.Question;
import top.tqx.demo_1.entity.UserAnswer;
import top.tqx.demo_1.enums.AnswerType;
import top.tqx.demo_1.service.AuthService;
import top.tqx.demo_1.service.AsyncExamService;
import top.tqx.demo_1.service.ExamPaperService;
import top.tqx.demo_1.service.ExamService;
import top.tqx.demo_1.service.ExamRecordService;
import top.tqx.demo_1.service.UserAnswerService;
import top.tqx.demo_1.service.UserService;
import top.tqx.demo_1.vo.UserVO;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Tag(name = "考试管理", description = "题目生成与答案批改接口")
@RestController
@RequestMapping("/exam")
@Slf4j
public class ExamController extends BaseController {

    @Autowired
    private ExamService examService;

    @Autowired
    private ExamPaperService examPaperService;

    @Autowired
    private AuthService authService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserAnswerService userAnswerService;

    @Autowired
    private top.tqx.demo_1.service.ExamRecordService examRecordService;

    @Autowired
    private AsyncExamService asyncExamService;

    @Operation(summary = "获取试卷详情", description = "通过试卷ID获取试卷详情")
    @GetMapping("/paper/{paperId}")
    public Result<ExamPaperResponse> getPaperById(
            @PathVariable String paperId) {
        try {
            ExamPaperResponse response = examPaperService.getPaperById(paperId);
            if (response == null) {
                return Result.error(404, "试卷不存在");
            }
            return Result.success(response);
        } catch (Exception e) {
            log.error("获取试卷详情失败: {}", e.getMessage());
            return Result.error(500, e.getMessage());
        }
    }

    @Operation(summary = "开始考试（获取题目）", description = "通过试卷ID开始模拟考试，同时返回试卷题目内容")
    @PostMapping("/paper/{paperId}/start")
    public Result<ExamRecordResponse> startExamByPaperId(
            @PathVariable String paperId,
            HttpServletRequest httpRequest) {
        try {
            Long userId = getCurrentUserId(httpRequest);
            ExamRecordResponse response = examRecordService.startExamByPaperId(paperId, userId, AnswerType.PRACTICE.getCode());
            return Result.success(response);
        } catch (Exception e) {
            log.error("开始考试失败: {}", e.getMessage());
            return Result.error(500, e.getMessage());
        }
    }

    @Operation(summary = "获取考试结果", description = "获取模拟考试的完整结果，包括题目、答案、分数等信息")
    @GetMapping("/record/{recordId}/result")
    public Result<ExamRecordResponse> getExamResult(
            @PathVariable String recordId,
            HttpServletRequest httpRequest) {
        try {
            Long userId = getCurrentUserId(httpRequest);
            ExamRecordResponse response = examRecordService.getRecordById(recordId);

            if (response == null) {
                return Result.error(404, "记录不存在");
            }

            if (!response.getUserId().equals(userId)) {
                return Result.error(403, "无权查看此记录");
            }

            return Result.success(response);
        } catch (Exception e) {
            log.error("获取考试结果失败: {}", e.getMessage());
            return Result.error(500, e.getMessage());
        }
    }

    @Operation(summary = "生成试卷", description = "根据权限范围从题库中动态生成试卷")
    @PostMapping("/paper/generate")
    public Result<ExamPaperGenerateResponse> generatePaper(
            @RequestBody ExamPaperGenerateRequest request,
            HttpServletRequest httpRequest) {

        Long userId = getCurrentUserId(httpRequest);
        if (userId == null) {
            return Result.error(401, "用户未登录");
        }

        UserVO userVO = userService.getUserById(userId);
        if (userVO == null) {
            return Result.error(401, "用户不存在");
        }

        if (request.getIncludePersonal() == null) {
            request.setIncludePersonal(false);
        }

        log.info("生成试卷请求: userId={}, deptId={}, userType={}, includePersonal={}, singleChoiceCount={}, multipleChoiceCount={}, trueFalseCount={}, fillBlankCount={}, subjectiveCount={}, difficulty={}",
                userId, userVO.getDeptId(), userVO.getUserType(), request.getIncludePersonal(),
                request.getSingleChoiceCount(), request.getMultipleChoiceCount(),
                request.getTrueFalseCount(), request.getFillBlankCount(),
                request.getSubjectiveCount(), request.getDifficulty());

        try {
            ExamPaperGenerateResponse response = examService.generatePaper(request, userId, userVO.getDeptId(), userVO.getUserType());
            return Result.success("试卷生成成功", response);
        } catch (Exception e) {
            log.error("生成试卷异常: {}", e.getMessage(), e);
            return Result.error(500, "生成试卷异常: " + e.getMessage());
        }
    }

    @Operation(summary = "生成题目（异步）", description = "根据知识库内容生成考试题目，支持单选题、多选题、判断题、填空题、简答题。支持两种模式：1. 智能生成模式（推荐）：不提供 question_types 参数，系统会调用 AI 智能出题接口 /exam/generate-smart，AI 会根据文档内容自动判断题型和数量；2. 指定题型模式：提供 question_types 参数，系统会调用传统出题接口 /exam/generate，按照指定的题型和数量生成题目。支持两种方式指定文件：通过 file_id 指定（推荐）或通过 file_path 指定。此接口为异步接口，请求后立即返回任务提交状态，实际生成在后台执行，需通过 GET /api/file/{fileId} 接口轮询查询生成进度和结果。")
    @PostMapping("/generate")
    public Result<Map<String, Object>> generateQuestions(
            @RequestBody ExamGenerateRequest request,
            HttpServletRequest httpRequest) {

        Long userId = getCurrentUserId(httpRequest);
        if (userId == null) {
            return Result.error(401, "用户未登录");
        }

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

        boolean hasFilePath = (request.getFilePath() != null && !request.getFilePath().isEmpty());
        boolean hasFileId = (request.getFileId() != null);

        if (!hasFilePath && !hasFileId) {
            feedback.put("errorType", "VALIDATION_ERROR");
            feedback.put("errorDetail", "file_path 和 file_id 不能同时为空");
            feedback.put("suggestion", "请通过 file_path 指定文件路径，或通过 file_id 指定文件ID");
            return Result.error(400, "参数验证失败", feedback);
        }

        if (hasFilePath && hasFileId) {
            feedback.put("warning", "同时提供了 file_path 和 file_id，将优先使用 file_id");
            log.warn("同时提供了 file_path 和 file_id，将优先使用 file_id");
        }

        if (request.getRequestId() == null || request.getRequestId().isEmpty()) {
            request.setRequestId(UUID.randomUUID().toString());
        }

        log.info("========== 生成题目请求开始 ==========");
        log.info("请求参数: userId={}, requestId={}, fileId={}, filePath={}, questionTypes={}, difficulty={}",
                userId, request.getRequestId(), request.getFileId(), request.getFilePath(),
                request.getQuestionTypes(), request.getDifficulty());

        try {
            Map<String, Object> result = examService.generateQuestionsWithFileId(request);

            feedback.putAll(result);
            feedback.put("status", "success");
            feedback.put("message", "收到请求，正在生成题目");

            // 触发异步任务生成题目
            asyncExamService.generateQuestionsAsync(request);

            return Result.success("收到请求", feedback);

        } catch (IllegalArgumentException e) {
            feedback.put("status", "error");
            feedback.put("errorType", "VALIDATION_ERROR");
            feedback.put("errorDetail", e.getMessage());
            feedback.put("suggestion", "请检查 file_id 是否正确或文件是否已上传");
            log.error("生成题目请求验证失败: {}", e.getMessage());
            return Result.error(400, "请求参数验证失败", feedback);

        } catch (Exception e) {
            feedback.put("status", "error");
            feedback.put("errorType", "INTERNAL_ERROR");
            feedback.put("errorDetail", e.getMessage());
            feedback.put("suggestion", "请稍后重试或联系管理员");
            log.error("生成题目请求处理失败", e);
            return Result.error(500, "服务器内部错误", feedback);
        }
    }

    @Operation(summary = "提交考试并批改（正式考试专用）", description = "通过考试记录ID提交正式考试答案并批改")
    @PostMapping("/record/{recordId}/grade")
    public Result<ExamRecordResponse> gradeExamRecord(
            @PathVariable String recordId,
            @RequestBody ExamSaveRequest request,
            HttpServletRequest httpRequest) {

        Long userId = getCurrentUserId(httpRequest);
        if (userId == null) {
            return Result.error(401, "用户未登录");
        }

        log.info("提交正式考试: userId={}, recordId={}", userId, recordId);

        try {
            ExamRecordResponse response = examService.gradeAnswersForRecord(recordId, request, userId, "formal_exam");
            return Result.success("提交成功", response);
        } catch (Exception e) {
            log.error("提交正式考试失败: {}", e.getMessage(), e);
            return Result.error(500, "提交失败: " + e.getMessage());
        }
    }

    @Operation(summary = "批改答案（日常练习/模拟考/正式考试通用）", description = "对学生提交的答案进行批改，支持客观题本地批改和主观题LLM评分")
    @PostMapping("/grade")
    public Result<Object> gradeAnswers(
            @RequestBody ExamGradeRequest request,
            HttpServletRequest httpRequest) {

        log.info("========== 批阅接口请求开始 ==========");
        log.info("请求完整内容: {}", JSON.toJSONString(request));

        Long userId = getCurrentUserId(httpRequest);
        if (userId == null) {
            log.error("用户未登录，无法进行批阅");
            return Result.error(401, "用户未登录，请先登录");
        }
        log.info("当前用户ID: {}", userId);

        if (request.getAnswers() == null) {
            log.warn("答案列表为null，视为空白试卷");
            request.setAnswers(new ArrayList<>());
        }
        log.info("答案数量: {}", request.getAnswers().size());

        if (request.getRecordId() != null && !request.getRecordId().isEmpty()) {
            log.info("检测到正式考试模式: recordId={}", request.getRecordId());

            ExamSaveRequest saveRequest = new ExamSaveRequest();
            List<ExamSaveRequest.AnswerItem> saveItems = request.getAnswers().stream().map(gradeItem -> {
                ExamSaveRequest.AnswerItem saveItem = new ExamSaveRequest.AnswerItem();
                saveItem.setQuestionId(gradeItem.getQuestionId());
                saveItem.setQuestionType(gradeItem.getQuestionType());
                saveItem.setAnswer(gradeItem.getStudentAnswer());
                return saveItem;
            }).collect(java.util.stream.Collectors.toList());
            saveRequest.setAnswers(saveItems);

            log.info("通过recordId提交考试: userId={}, recordId={}, 答案数量={}", userId, request.getRecordId(), saveItems.size());

            try {
                ExamRecordResponse response = examService.gradeAnswersForRecord(
                    request.getRecordId(),
                    saveRequest,
                    userId,
                    request.getAnswerType() != null ? request.getAnswerType() : "formal_exam");
                log.info("正式考试批阅成功: recordId={}", request.getRecordId());
                return Result.success("批阅成功", response);
            } catch (Exception e) {
                log.error("正式考试批改失败: recordId={}, 错误类型={}, 错误信息={}", request.getRecordId(), e.getClass().getName(), e.getMessage(), e);
                String detailedError = String.format("批改失败: %s - %s", e.getClass().getSimpleName(), e.getMessage());
                return Result.error(500, detailedError);
            }
        }

        log.info("日常练习/模拟考模式，开始验证答案数据...");

        // 检查是否为空试卷
        boolean isBlankSubmission = request.getAnswers().isEmpty();
        
        if (!isBlankSubmission) {
            for (int i = 0; i < request.getAnswers().size(); i++) {
                ExamGradeRequest.AnswerItem answer = request.getAnswers().get(i);
                log.debug("验证第{}个答案: questionId={}, questionType={}", i+1, answer.getQuestionId(), answer.getQuestionType());

                if (answer.getQuestionId() == null || answer.getQuestionId().isEmpty()) {
                    log.error("第{}个答案缺少questionId", i+1);
                    return Result.error(400, String.format("第%d个答案的questionId不能为空", i+1));
                }
                if (answer.getQuestionType() == null || answer.getQuestionType().isEmpty()) {
                    log.error("第{}个答案缺少questionType, questionId={}", i+1, answer.getQuestionId());
                    return Result.error(400, String.format("第%d个答案的questionType不能为空 (questionId: %s)", i+1, answer.getQuestionId()));
                }
                if (answer.getQuestionContent() == null) {
                    log.error("第{}个答案缺少questionContent, questionId={}", i+1, answer.getQuestionId());
                    return Result.error(400, String.format("第%d个答案的questionContent不能为空 (questionId: %s)", i+1, answer.getQuestionId()));
                }
                if (answer.getMaxScore() == null) {
                    log.error("第{}个答案缺少maxScore, questionId={}", i+1, answer.getQuestionId());
                    return Result.error(400, String.format("第%d个答案的maxScore不能为空 (questionId: %s)", i+1, answer.getQuestionId()));
                }

                String validTypes = "single_choice,multiple_choice,true_false,fill_blank,subjective";
                if (!validTypes.contains(answer.getQuestionType())) {
                    log.error("第{}个答案的题型无效: {}, 有效题型: {}", i+1, answer.getQuestionType(), validTypes);
                    return Result.error(400, String.format("第%d个答案的questionType无效: %s (有效值: %s)", i+1, answer.getQuestionType(), validTypes));
                }
            }
        }
        log.info("答案数据验证通过，共{}个答案{}", request.getAnswers().size(), isBlankSubmission ? "（空白试卷）" : "");
        log.info("空试卷标记: isBlankSubmission={}", isBlankSubmission);

        if (request.getRequestId() == null || request.getRequestId().isEmpty()) {
            request.setRequestId(UUID.randomUUID().toString());
            log.info("自动生成requestId: {}", request.getRequestId());
        }

        if (request.getPaperId() == null || request.getPaperId().isEmpty()) {
            String generatedPaperId = UUID.randomUUID().toString();
            request.setPaperId(generatedPaperId);
            log.info("自动生成试卷ID: paperId={}", generatedPaperId);
        }

        if (request.getSessionId() == null || request.getSessionId().isEmpty()) {
            request.setSessionId("grade_" + UUID.randomUUID().toString().substring(0, 8));
            log.info("自动生成sessionId: {}", request.getSessionId());
        }

        log.info("========== 准备调用批阅服务 ==========");
        log.info("批改答案请求参数汇总:");
        log.info("  - userId: {}", userId);
        log.info("  - requestId: {}", request.getRequestId());
        log.info("  - paperId: {}", request.getPaperId());
        log.info("  - sessionId: {}", request.getSessionId());
        log.info("  - answerType: {}", request.getAnswerType());
        log.info("  - answers count: {}", request.getAnswers().size());

        try {
            ExamGradeResponse response = examService.gradeAnswers(request, userId, request.getPaperId(),
                    request.getSessionId(), request.getAnswerType());

            if (Boolean.TRUE.equals(response.getSuccess())) {
                log.info("========== 批阅成功 ==========");
                log.info("批阅结果: totalScore={}, totalMaxScore={}, scoreRate={}%",
                        response.getTotalScore(), response.getTotalMaxScore(), response.getScoreRate());
                
                // 保存答题记录到数据库
                saveUserAnswers(request, response, userId);
                
                return Result.success("批阅成功", response);
            } else {
                String errorMessage = response.getError() != null ? response.getError() : "答案批改失败";
                log.error("========== 批阅失败 ==========");
                log.error("失败原因: {}", errorMessage);
                return Result.error(500, errorMessage);
            }

        } catch (IOException e) {
            log.error("========== 批改答案IO异常 ==========");
            log.error("错误类型: IOException");
            log.error("错误信息: {}", e.getMessage());
            log.error("可能的原因:");
            log.error("  1. AI服务连接超时");
            log.error("  2. 网络不稳定");
            log.error("  3. AI服务响应格式错误");
            log.error("详细堆栈: ", e);
            String detailedError = String.format("批改答案失败（IO异常）: %s", e.getMessage());
            return Result.error(500, detailedError);
        } catch (Exception e) {
            log.error("========== 批改答案发生未知异常 ==========");
            log.error("错误类型: {}", e.getClass().getName());
            log.error("错误信息: {}", e.getMessage());
            log.error("可能的错误位置:");
            for (StackTraceElement element : e.getStackTrace()) {
                if (element.getClassName().contains("top.tqx")) {
                    log.error("  at {}.{}:{} (行号: {})",
                            element.getClassName(), element.getMethodName(),
                            element.getFileName(), element.getLineNumber());
                }
            }
            log.error("完整堆栈: ", e);

            String detailedError = String.format("批改答案发生未知异常: %s - %s",
                    e.getClass().getSimpleName(), e.getMessage());
            return Result.error(500, detailedError);
        }
    }

    @Operation(summary = "查询用户答题记录", description = "根据试卷ID或会话ID查询用户答题记录，支持按试卷/练习维度分组展示")
    @PostMapping("/answers/query")
    public Result<UserAnswerQueryResponse> queryUserAnswers(
            @RequestBody UserAnswerQueryRequest request,
            HttpServletRequest httpRequest) {

        Long userId = getCurrentUserId(httpRequest);
        if (userId == null) {
            return Result.error(401, "用户未登录");
        }

        boolean hasPaperId = request.getPaperId() != null && !request.getPaperId().isEmpty();
        boolean hasSessionId = request.getSessionId() != null && !request.getSessionId().isEmpty();

        if (!hasPaperId && !hasSessionId) {
            return Result.error(400, "paper_id 或 session_id 不能为空");
        }

        if (hasPaperId && hasSessionId) {
            return Result.error(400, "paper_id 和 session_id 不能同时提供");
        }

        request.setUserId(userId);

        log.info("查询用户答题记录: userId={}, paperId={}, sessionId={}",
                userId, request.getPaperId(), request.getSessionId());

        try {
            UserAnswerQueryResponse response = userAnswerService.queryUserAnswers(request);

            if (response.getTotalCount() == 0) {
                return Result.success("未找到答题记录", response);
            }

            return Result.success("查询成功", response);

        } catch (Exception e) {
            log.error("查询用户答题记录异常: {}", e.getMessage(), e);
            return Result.error(500, "查询用户答题记录异常: " + e.getMessage());
        }
    }

    @Operation(summary = "获取考试记录列表", description = "根据类型获取用户的考试/练习记录，支持日常练习(practice)、模拟考(mock_exam)、正式考(formal_exam)")
    @GetMapping("/records")
    public Result<Object> getExamRecords(
            @Parameter(description = "记录类型：practice(日常练习), mock_exam(模拟考), formal_exam(正式考)", example = "practice")
            @RequestParam(defaultValue = "practice") String type,
            HttpServletRequest httpRequest) {

        Long userId = getCurrentUserId(httpRequest);
        if (userId == null) {
            return Result.error(401, "用户未登录");
        }

        log.info("查询考试记录: userId={}, type={}", userId, type);

        try {
            if ("practice".equals(type)) {
                UserAnswerQueryRequest queryRequest = new UserAnswerQueryRequest();
                queryRequest.setUserId(userId);
                UserAnswerQueryResponse response = userAnswerService.queryUserAnswers(queryRequest);
                return Result.success(response);
            } else if ("mock_exam".equals(type) || "formal_exam".equals(type)) {
                List<ExamRecordResponse> records = examRecordService.getUserPapers(userId, type);
                return Result.success(records);
            } else {
                return Result.error(400, "无效的类型参数，支持的值: practice, mock_exam, formal_exam");
            }
        } catch (Exception e) {
            log.error("查询考试记录失败: {}", e.getMessage(), e);
            return Result.error(500, "查询考试记录失败: " + e.getMessage());
        }
    }

    /**
     * 保存用户答题记录到数据库
     */
    private void saveUserAnswers(ExamGradeRequest request, ExamGradeResponse response, Long userId) {
        ObjectMapper objectMapper = new ObjectMapper();
        List<UserAnswer> userAnswers = new ArrayList<>();
        
        List<ExamGradeResponse.GradeResult> results = response.getResults();
        if (results == null || results.isEmpty()) {
            log.warn("没有答题结果需要保存");
            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(request.getAnswerType() != null ? request.getAnswerType() : "practice");
            userAnswer.setPaperId(request.getPaperId());
            userAnswer.setSessionId(request.getSessionId());
            userAnswer.setScore(result.getScore());
            userAnswer.setMaxScore(result.getMaxScore() != null ? result.getMaxScore() : answerItem.getMaxScore());
            
            // 转换学生答案为JSON
            try {
                JsonNode answerNode = objectMapper.valueToTree(answerItem.getStudentAnswer());
                userAnswer.setUserAnswer(answerNode);
            } catch (Exception e) {
                log.warn("转换学生答案为JSON失败", e);
            }
            
            // 设置是否正确
            Boolean isCorrect = result.getCorrect() != null ? result.getCorrect() : result.getIsCorrect();
            if (Boolean.TRUE.equals(isCorrect)) {
                userAnswer.setIsCorrect(1);
            } else {
                userAnswer.setIsCorrect(0);
            }
            
            userAnswer.setGradingType("ai");
            userAnswer.setFeedback(result.getFeedback());
            userAnswer.setCreatedAt(LocalDateTime.now());
            userAnswer.setUpdatedAt(LocalDateTime.now());
            
            userAnswers.add(userAnswer);
        }
        
        // 批量保存答题记录
        userAnswerService.batchSaveAnswers(userAnswers);
        log.info("成功保存 {} 条答题记录到数据库", userAnswers.size());
    }

}
