package cn.yunzhixue.ability.center.examsprint.application.report;

import cn.yunzhixue.ability.center.examsprint.contracts.report.AchievementExamSprintReportPayload;
import cn.yunzhixue.ability.center.examsprint.domain.report.AchievementReportContent;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class AchievementReportContentMapperTest {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Test
    void mapsCallerPascalCasePayloadToExistingAchievementContent() {
        AchievementReportContent content = AchievementReportContentMapper.toDomainContent(payload());

        assertThat(content.studentName()).isEqualTo("吴泓妤");
        assertThat(content.reportTitle()).isEqualTo("高考英语临考突击学习成果报告");
        assertThat(content.reportSubtitle()).isEqualTo("2024真题 · 临考突击 · 真实提分效果");
        assertThat(content.completionTitle()).isEqualTo("恭喜完成临考突击专项训练");
        assertThat(content.completionSubtitle()).isEqualTo("基于2024真题 · 真实学习效果分析");
        assertThat(content.summaryMetrics().vocabularyGrowthText()).isEqualTo("+19");
        assertThat(content.summaryMetrics().paperKnownWordsGrowthText()).isEqualTo("+4");
        assertThat(content.summaryMetrics().unknownWordHitRateText()).isEqualTo("1.93%");
        assertThat(content.summaryMetrics().learningEfficiencyText()).isEqualTo("0.48");
        assertThat(content.vocabularyComparison().beforeValue()).isEqualTo(2328.0);
        assertThat(content.vocabularyComparison().afterText()).isEqualTo("2347");
        assertThat(content.vocabularyComparison().growthText()).isEqualTo("+19");
        assertThat(content.stageVocabularySummary().stageName()).isEqualTo("高考");
        assertThat(content.stageVocabularySummary().stageVocabularyText()).isEqualTo("3500");
        assertThat(content.stageVocabularySummary().masteryBeforeText()).isEqualTo("66.51");
        assertThat(content.stageVocabularySummary().masteryAfterText()).isEqualTo("67.06");
        assertThat(content.stageVocabularySummary().masteryImprovementText()).isEqualTo("+0.55");
        assertThat(content.paperKnownWordsComparison().beforeValue()).isEqualTo(650.0);
        assertThat(content.paperKnownWordsComparison().afterText()).isEqualTo("654");
        assertThat(content.paperKnownWordsComparison().growthText()).isEqualTo("+4");
        assertThat(content.testPaperVocabularySummary().testPaperTitle()).isEqualTo("2024真题");
        assertThat(content.testPaperVocabularySummary().testPaperWordCountText()).isEqualTo("861");
        assertThat(content.testPaperVocabularySummary().unknownWordsBeforeText()).isEqualTo("207");
        assertThat(content.testPaperVocabularySummary().unknownWordsAfterText()).isEqualTo("203");
        assertThat(content.testPaperVocabularySummary().masteryRateBeforeText()).isEqualTo("75.49");
        assertThat(content.testPaperVocabularySummary().masteryRateAfterText()).isEqualTo("75.96");
        assertThat(content.testPaperVocabularySummary().masteryRateImprovementText()).isEqualTo("+0.62");
        assertThat(content.examUnknownWordsHitStatus().unknownWordHitRateText()).isEqualTo("1.93%");
        assertThat(content.examUnknownWordsHitStatus().learningEfficiencyText()).isEqualTo("0.48");
        assertThat(content.examUnknownWordsHitStatus().unknownWordsBeforeText()).isEqualTo("207");
        assertThat(content.examUnknownWordsHitStatus().unknownWordsAfterText()).isEqualTo("203");
        assertThat(content.examUnknownWordsHitStatus().reducedUnknownWordsText()).isEqualTo("4");
        assertThat(content.examUnknownWordsHitStatus().hitWords())
                .containsExactly("number", "bear", "popular", "importance");
    }

    @Test
    void mapsNegativeSignedGrowthAndDoesNotDuplicateEnglishInReportTitle() {
        ObjectNode payload = pascalPayload();
        payload.put("StageName", "高考英语");
        payload.put("StudentImproveWordCount", -2);
        payload.put("StudentVocabularyBefore", 2349);
        payload.put("StudentVocabulary", 2347);
        payload.put("StudentVocabMasteryImprovement", -0.04);

        AchievementReportContent content = AchievementReportContentMapper.toDomainContent(convert(payload));

        assertThat(content.reportTitle()).isEqualTo("高考英语临考突击学习成果报告");
        assertThat(content.summaryMetrics().vocabularyGrowthText()).isEqualTo("-2");
        assertThat(content.vocabularyComparison().growthText()).isEqualTo("-2");
        assertThat(content.stageVocabularySummary().masteryImprovementText()).isEqualTo("-0.04");
    }

    @Test
    void filtersBlankImprovedWordsFromStringAndObjectElements() {
        ObjectNode payload = pascalPayload();
        payload.putArray("TestPaperImprovedWords")
                .add(" number ")
                .add("   ")
                .add(OBJECT_MAPPER.createObjectNode().put("WordSpell", " bear "))
                .add(OBJECT_MAPPER.createObjectNode().put("WordSpell", "\t"));

        AchievementReportContent content = AchievementReportContentMapper.toDomainContent(convert(payload));

        assertThat(content.examUnknownWordsHitStatus().hitWords()).containsExactly("number", "bear");
    }

    @Test
    void rejectsNullPayload() {
        assertThatThrownBy(() -> AchievementReportContentMapper.toDomainContent(null))
                .isInstanceOf(NullPointerException.class)
                .hasMessageContaining("payload");
    }

    private AchievementExamSprintReportPayload payload() {
        return convert(pascalPayload());
    }

    private AchievementExamSprintReportPayload convert(ObjectNode payload) {
        return OBJECT_MAPPER.convertValue(payload, AchievementExamSprintReportPayload.class);
    }

    private ObjectNode pascalPayloadWithRemainingNumbers(ObjectNode payload) {
        return payload
                .put("TestPaperImprovedWordCount", 4)
                .put("TestPaperImproveRate", 0.62)
                .put("PaperMasteryHitRate", 1.9300)
                .put("ImproveStudyEfficiency", 0.48)
                .put("StudentInitialVocabMastery", 66.51)
                .put("StudentCurrentVocabMastery", 67.06)
                .put("StudentVocabMasteryImprovement", 0.55)
                .put("TestPaperBeforMasteryRate", 75.49)
                .put("TestPaperLatestMasteryRate", 75.96)
                .put("ShouldDisplaySigningGuarantee", true)
                .put("SigningGuarantee", "签约保障");
    }

    private ObjectNode pascalPayload() {
        return pascalPayloadWithRemainingNumbers(basePascalPayload());
    }

    private ObjectNode basePascalPayload() {
        return (ObjectNode) OBJECT_MAPPER.createObjectNode()
                .put("StudentName", "吴泓妤")
                .put("StudentStage", 3)
                .put("StageName", "高考")
                .put("StageVocabulary", 3500)
                .put("StudentVocabulary", 2347)
                .put("StudentVocabularyBefore", 2328)
                .put("StudentUnMastedWordCount", 1153)
                .put("StudentImproveWordCount", 19)
                .put("TestPaperTitle", "2024真题")
                .put("TestPaperWordCount", 861)
                .put("TestPaperBeforUnMastery", 207)
                .put("TestPaperBeforMastery", 650)
                .put("TestPaperLatestMastery", 654)
                .put("TestPaperAfterUnMastery", 203)
                .set("TestPaperImprovedWords", OBJECT_MAPPER.createArrayNode()
                        .add(" number ")
                        .add(OBJECT_MAPPER.createObjectNode().put("WordSpell", "bear"))
                        .add(OBJECT_MAPPER.createObjectNode().put("WordSpell", " popular "))
                        .add("importance"));
    }
}
