package top.tqx.demo_1;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import top.tqx.demo_1.dto.ExamGenerateRequest;
import top.tqx.demo_1.dto.ExamGenerateResponse;
import top.tqx.demo_1.dto.ExamGradeRequest;
import top.tqx.demo_1.dto.ExamGradeResponse;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;

class ExamServiceTest {

    private ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        objectMapper = new ObjectMapper();
    }

    @Test
    @DisplayName("测试 ExamGenerateRequest 序列化")
    void testExamGenerateRequestSerialization() throws Exception {
        ExamGenerateRequest request = new ExamGenerateRequest();
        request.setRequestId("test-request-001");
        request.setQuestionCount(10);
        request.setQuestionTypes(Arrays.asList("single_choice", "multiple_choice"));
        request.setDifficulty(3);
        request.setCollectionName("test-collection");
        request.setFilePath("/documents/test.pdf");
        request.setTags(Arrays.asList("tag1", "tag2"));

        String json = objectMapper.writeValueAsString(request);
        assertNotNull(json);
        assertTrue(json.contains("\"request_id\":\"test-request-001\""));
        assertTrue(json.contains("\"question_count\":10"));
        assertTrue(json.contains("\"difficulty\":3"));
        assertTrue(json.contains("\"collection_name\":\"test-collection\""));
    }

    @Test
    @DisplayName("测试 ExamGenerateResponse 解析")
    void testExamGenerateResponseDeserialization() throws Exception {
        String jsonResponse = """
            {
              "success": true,
              "request_id": "xxx",
              "total": 10,
              "source_chunks_used": 15,
              "questions": [
                {
                  "question_type": "single_choice",
                  "difficulty": 3,
                  "content": {
                    "stem": "题干内容",
                    "data": {
                      "options": [
                        {"key": "A", "content": "选项A"},
                        {"key": "B", "content": "选项B"},
                        {"key": "C", "content": "选项C"},
                        {"key": "D", "content": "选项D"}
                      ]
                    },
                    "answer": "B",
                    "explanation": "答案解析"
                  },
                  "source_trace": {
                    "document_name": "考勤制度.docx",
                    "chunk_ids": ["chunk_001"],
                    "page_numbers": [5],
                    "sources": [
                      {
                        "chunk_id": "chunk_001",
                        "page": 5,
                        "section": "请假制度",
                        "snippet": "原文片段..."
                      }
                    ]
                  }
                }
              ]
            }
            """;

        ExamGenerateResponse response = objectMapper.readValue(jsonResponse, ExamGenerateResponse.class);

        assertTrue(response.getSuccess());
        assertEquals("xxx", response.getRequestId());
        assertEquals(10, response.getTotal());
        assertEquals(15, response.getSourceChunksUsed());
        assertNotNull(response.getQuestions());
        assertEquals(1, response.getQuestions().size());

        ExamGenerateRequest.Question question = response.getQuestions().get(0);
        assertEquals("single_choice", question.getQuestionType());
        assertEquals(3, question.getDifficulty());
        assertEquals("题干内容", question.getContent().getStem());
        assertEquals("B", question.getContent().getAnswer());
        assertEquals("答案解析", question.getContent().getExplanation());
        assertEquals("考勤制度.docx", question.getSourceTrace().getDocumentName());
    }

    @Test
    @DisplayName("测试 ExamGradeRequest 序列化")
    void testExamGradeRequestSerialization() throws Exception {
        ExamGradeRequest request = new ExamGradeRequest();
        request.setRequestId("grade-request-001");

        ExamGradeRequest.AnswerItem answer1 = new ExamGradeRequest.AnswerItem();
        answer1.setQuestionId("uuid-001");
        answer1.setQuestionType("single_choice");
        answer1.setMaxScore(BigDecimal.valueOf(2.0));

        ExamGradeRequest.QuestionContent content1 = new ExamGradeRequest.QuestionContent();
        content1.setStem("单选题题干");
        Map<String, Object> data1 = new HashMap<>();
        data1.put("options", Arrays.asList(
            Map.of("key", "A", "content", "选项A"),
            Map.of("key", "B", "content", "选项B")
        ));
        content1.setData(data1);
        content1.setAnswer("B");
        answer1.setQuestionContent(content1);
        answer1.setStudentAnswer("A");

        request.setAnswers(Arrays.asList(answer1));

        String json = objectMapper.writeValueAsString(request);
        assertNotNull(json);
        assertTrue(json.contains("\"question_id\":\"uuid-001\""));
        assertTrue(json.contains("\"question_type\":\"single_choice\""));
        assertTrue(json.contains("\"student_answer\":\"A\""));
    }

    @Test
    @DisplayName("测试 ExamGradeResponse 解析")
    void testExamGradeResponseDeserialization() throws Exception {
        String jsonResponse = """
            {
              "success": true,
              "request_id": "grade-request-001",
              "total_score": 12.5,
              "total_max_score": 22.0,
              "score_rate": 56.8,
              "results": [
                {
                  "question_id": "uuid-001",
                  "score": 0,
                  "max_score": 2.0,
                  "correct": false,
                  "feedback": "正确答案: B"
                },
                {
                  "question_id": "uuid-004",
                  "score": 2.0,
                  "max_score": 4.0,
                  "details": {
                    "blank_scores": [2.0, 0],
                    "correct_answers": [["答案1", "同义词1"], ["答案2"]]
                  }
                },
                {
                  "question_id": "uuid-005",
                  "score": 7.5,
                  "max_score": 10.0,
                  "details": {
                    "scoring_breakdown": [
                      {"point": "要点1", "weight": 0.4, "achieved": 0.35, "comment": "部分掌握"},
                      {"point": "要点2", "weight": 0.6, "achieved": 0.55, "comment": "基本掌握"}
                    ],
                    "highlights": ["思路清晰"],
                    "shortcomings": ["细节不够完整"],
                    "overall_feedback": "整体回答良好，建议补充细节。"
                  }
                }
              ]
            }
            """;

        ExamGradeResponse response = objectMapper.readValue(jsonResponse, ExamGradeResponse.class);

        assertTrue(response.getSuccess());
        assertEquals("grade-request-001", response.getRequestId());
        assertEquals(0, response.getTotalScore().compareTo(BigDecimal.valueOf(12.5)));
        assertEquals(0, response.getTotalMaxScore().compareTo(BigDecimal.valueOf(22.0)));
        assertEquals(0, response.getScoreRate().compareTo(BigDecimal.valueOf(56.8)));
        assertNotNull(response.getResults());
        assertEquals(3, response.getResults().size());

        ExamGradeResponse.GradeResult result1 = response.getResults().get(0);
        assertEquals("uuid-001", result1.getQuestionId());
        assertFalse(result1.getCorrect());
        assertEquals("正确答案: B", result1.getFeedback());

        ExamGradeResponse.GradeResult result2 = response.getResults().get(1);
        assertEquals("uuid-004", result2.getQuestionId());
        assertNotNull(result2.getDetails());
        assertEquals(2, result2.getDetails().getBlankScores().size());

        ExamGradeResponse.GradeResult result3 = response.getResults().get(2);
        assertNotNull(result3.getDetails());
        assertNotNull(result3.getDetails().getScoringBreakdown());
        assertEquals(2, result3.getDetails().getScoringBreakdown().size());
        assertEquals("思路清晰", result3.getDetails().getHighlights().get(0));
    }

    @Test
    @DisplayName("测试错误响应格式解析")
    void testErrorResponseDeserialization() throws Exception {
        String jsonResponse = """
            {
              "success": false,
              "error": "文件内容为空，无法出题",
              "error_code": "NO_CONTENT"
            }
            """;

        ExamGenerateResponse response = objectMapper.readValue(jsonResponse, ExamGenerateResponse.class);

        assertFalse(response.getSuccess());
        assertEquals("文件内容为空，无法出题", response.getError());
        assertEquals("NO_CONTENT", response.getErrorCode());
    }

    @Test
    @DisplayName("测试各题型answer格式")
    void testQuestionTypeAnswerFormats() throws Exception {
        String jsonResponse = """
            {
              "success": true,
              "questions": [
                {"question_type": "single_choice", "content": {"answer": "B"}},
                {"question_type": "multiple_choice", "content": {"answer": ["A", "C"]}},
                {"question_type": "true_false", "content": {"answer": true}},
                {"question_type": "fill_blank", "content": {"answer": [["答案1"], ["答案2", "同义词"]]}},
                {"question_type": "subjective", "content": {"answer": "参考范文..."}}
              ]
            }
            """;

        ExamGenerateResponse response = objectMapper.readValue(jsonResponse, ExamGenerateResponse.class);

        assertEquals(5, response.getQuestions().size());
        assertEquals("B", response.getQuestions().get(0).getContent().getAnswer());
        assertTrue(response.getQuestions().get(1).getContent().getAnswer() instanceof List);
        assertTrue(response.getQuestions().get(2).getContent().getAnswer() instanceof Boolean);
        assertTrue(response.getQuestions().get(3).getContent().getAnswer() instanceof List);
        assertEquals("参考范文...", response.getQuestions().get(4).getContent().getAnswer());
    }

    @Test
    @DisplayName("测试多选题学生答案格式")
    void testMultipleChoiceStudentAnswer() throws Exception {
        ExamGradeRequest request = new ExamGradeRequest();

        ExamGradeRequest.AnswerItem answer = new ExamGradeRequest.AnswerItem();
        answer.setQuestionId("uuid-002");
        answer.setQuestionType("multiple_choice");
        answer.setMaxScore(BigDecimal.valueOf(4.0));
        answer.setStudentAnswer(Arrays.asList("A", "B"));

        request.setAnswers(Arrays.asList(answer));

        String json = objectMapper.writeValueAsString(request);
        assertNotNull(json);
        assertTrue(json.contains("\"student_answer\":[\"A\",\"B\"]"));
    }

    @Test
    @DisplayName("测试填空题学生答案格式")
    void testFillBlankStudentAnswer() throws Exception {
        ExamGradeRequest request = new ExamGradeRequest();

        ExamGradeRequest.AnswerItem answer = new ExamGradeRequest.AnswerItem();
        answer.setQuestionId("uuid-004");
        answer.setQuestionType("fill_blank");
        answer.setMaxScore(BigDecimal.valueOf(4.0));
        answer.setStudentAnswer(Arrays.asList("学生答案1", "学生答案2"));

        request.setAnswers(Arrays.asList(answer));

        String json = objectMapper.writeValueAsString(request);
        assertNotNull(json);
        assertTrue(json.contains("\"student_answer\":[\"学生答案1\",\"学生答案2\"]"));
    }

    @Test
    @DisplayName("测试主观题学生答案格式")
    void testSubjectiveStudentAnswer() throws Exception {
        ExamGradeRequest request = new ExamGradeRequest();

        ExamGradeRequest.AnswerItem answer = new ExamGradeRequest.AnswerItem();
        answer.setQuestionId("uuid-005");
        answer.setQuestionType("subjective");
        answer.setMaxScore(BigDecimal.valueOf(10.0));
        answer.setStudentAnswer("学生作答的长文本内容...");

        request.setAnswers(Arrays.asList(answer));

        String json = objectMapper.writeValueAsString(request);
        assertNotNull(json);
        assertTrue(json.contains("\"student_answer\":\"学生作答的长文本内容...\""));
    }

    @Test
    @DisplayName("测试题目内容结构完整性")
    void testQuestionContentStructure() throws Exception {
        String jsonResponse = """
            {
              "success": true,
              "questions": [
                {
                  "question_type": "single_choice",
                  "difficulty": 3,
                  "content": {
                    "stem": "这是题干",
                    "data": {
                      "options": [
                        {"key": "A", "content": "选项A"},
                        {"key": "B", "content": "选项B"},
                        {"key": "C", "content": "选项C"},
                        {"key": "D", "content": "选项D"}
                      ]
                    },
                    "answer": "B",
                    "explanation": "这是解析"
                  },
                  "source_trace": {
                    "document_name": "测试文档.docx",
                    "chunk_ids": ["chunk_001", "chunk_002"],
                    "page_numbers": [1, 2],
                    "sources": [
                      {
                        "chunk_id": "chunk_001",
                        "page": 1,
                        "section": "第一章",
                        "snippet": "原文片段1..."
                      },
                      {
                        "chunk_id": "chunk_002",
                        "page": 2,
                        "section": "第二章",
                        "snippet": "原文片段2..."
                      }
                    ]
                  }
                }
              ]
            }
            """;

        ExamGenerateResponse response = objectMapper.readValue(jsonResponse, ExamGenerateResponse.class);

        ExamGenerateRequest.Question question = response.getQuestions().get(0);
        assertEquals("single_choice", question.getQuestionType());
        assertEquals(3, question.getDifficulty());

        ExamGenerateRequest.QuestionContent content = question.getContent();
        assertEquals("这是题干", content.getStem());
        assertNotNull(content.getData());
        assertEquals("B", content.getAnswer());
        assertEquals("这是解析", content.getExplanation());

        ExamGenerateRequest.SourceTrace sourceTrace = question.getSourceTrace();
        assertEquals("测试文档.docx", sourceTrace.getDocumentName());
        assertEquals(2, sourceTrace.getChunkIds().size());
        assertEquals(2, sourceTrace.getPageNumbers().size());
        assertEquals(2, sourceTrace.getSources().size());
        assertEquals("chunk_001", sourceTrace.getSources().get(0).getChunkId());
        assertEquals(1, sourceTrace.getSources().get(0).getPage());
        assertEquals("第一章", sourceTrace.getSources().get(0).getSection());
    }

    @Test
    @DisplayName("测试批量答案批改请求")
    void testBatchGradeRequest() throws Exception {
        ExamGradeRequest request = new ExamGradeRequest();
        request.setRequestId("batch-grade-001");

        List<ExamGradeRequest.AnswerItem> answers = new ArrayList<>();

        ExamGradeRequest.AnswerItem singleChoice = new ExamGradeRequest.AnswerItem();
        singleChoice.setQuestionId("q-001");
        singleChoice.setQuestionType("single_choice");
        singleChoice.setMaxScore(BigDecimal.valueOf(2.0));
        ExamGradeRequest.QuestionContent c1 = new ExamGradeRequest.QuestionContent();
        c1.setStem("题干");
        c1.setAnswer("B");
        singleChoice.setQuestionContent(c1);
        singleChoice.setStudentAnswer("A");
        answers.add(singleChoice);

        ExamGradeRequest.AnswerItem multipleChoice = new ExamGradeRequest.AnswerItem();
        multipleChoice.setQuestionId("q-002");
        multipleChoice.setQuestionType("multiple_choice");
        multipleChoice.setMaxScore(BigDecimal.valueOf(4.0));
        ExamGradeRequest.QuestionContent c2 = new ExamGradeRequest.QuestionContent();
        c2.setStem("多选题题干");
        c2.setAnswer(Arrays.asList("A", "C"));
        multipleChoice.setQuestionContent(c2);
        multipleChoice.setStudentAnswer(Arrays.asList("A", "B"));
        answers.add(multipleChoice);

        ExamGradeRequest.AnswerItem trueFalse = new ExamGradeRequest.AnswerItem();
        trueFalse.setQuestionId("q-003");
        trueFalse.setQuestionType("true_false");
        trueFalse.setMaxScore(BigDecimal.valueOf(2.0));
        ExamGradeRequest.QuestionContent c3 = new ExamGradeRequest.QuestionContent();
        c3.setStem("判断题题干");
        c3.setAnswer(true);
        trueFalse.setQuestionContent(c3);
        trueFalse.setStudentAnswer(false);
        answers.add(trueFalse);

        request.setAnswers(answers);

        String json = objectMapper.writeValueAsString(request);
        assertNotNull(json);
        assertEquals(3, request.getAnswers().size());
    }
}