package com.yinlihupo.enlish.service.service.student;


import com.yinlihupo.enlish.service.constant.StudentConstant;
import com.yinlihupo.enlish.service.domain.dataobject.*;
import com.yinlihupo.enlish.service.domain.mapper.*;
import com.yinlihupo.enlish.service.model.bo.StudentDetail;
import com.yinlihupo.enlish.service.model.bo.exam.ExamWordsJudgeResultDetail;
import com.yinlihupo.enlish.service.model.bo.exam.WordMasteryDetail;
import com.yinlihupo.enlish.service.model.vo.student.AddStudentReqVO;
import com.yinlihupo.enlish.service.service.StudentService;
import com.yinlihupo.enlish.service.utils.DifyClient;
import com.yinlihupo.framework.common.util.JsonUtils;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class StudentServiceImpl implements StudentService {

    @Resource
    private StudentDOMapper studentDOMapper;
    @Resource
    private GradeDOMapper gradeDOMapper;
    @Resource
    private ClassDOMapper classDOMapper;
    @Resource
    private VocabularyBankDOMapper vocabularyBankMapper;
    @Resource
    private WordMasteryLogDOMapper wordMasteryLogDOMapper;
    @Resource
    private ExamWordsJudgeResultDOMapper examWordsJudgeResultDOMapper;
    @Resource
    private DifyClient difyClient;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private StudentStageLearningRemarkDOMapper studentStageLearningRemarkDOMapper;

    @Override
    public List<StudentDO> getStudentsByClassIdAndGradeId(Integer classId, Integer gradeId, String name, Integer pageNo, Integer pageSize) {

        return studentDOMapper.selectStudentDOListByClassIdAndGradeId(classId, gradeId, name, (pageNo - 1) * pageSize, pageSize);
    }

    @Override
    public int getAllStudents() {
        return studentDOMapper.selectStudentCount();
    }

    @Override
    public StudentDO getStudentById(Integer studentId) {
        return studentDOMapper.selectStudentById(studentId);
    }

    @Override
    public List<StudentDetail> getStudentDetailList(List<Integer> studentIdList) {

        List<StudentDO> studentDOS = studentDOMapper.selectStudentDOListByIds(studentIdList);
        Map<Integer, GradeDO> gradeId2GradeDO = gradeDOMapper.selectByGradeIds(studentDOS.stream().map(StudentDO::getGradeId).toList()).stream().collect(Collectors.toMap(
                GradeDO::getId,
                gradeDO -> gradeDO
        ));
        Map<Integer, ClassDO> classId2ClassDO = classDOMapper.selectClassDOListByIds(studentDOS.stream().map(StudentDO::getClassId).toList()).stream().collect(Collectors.toMap(
                ClassDO::getId,
                classDO -> classDO
        ));

        return studentDOS.stream().map(studentDO -> StudentDetail.builder()
                .id(studentDO.getId())
                .name(studentDO.getName())
                .classId(studentDO.getClassId())
                .className(classId2ClassDO.get(studentDO.getClassId()) != null ? classId2ClassDO.get(studentDO.getClassId()).getTitle() : "")
                .gradeId(studentDO.getGradeId())
                .gradeName(gradeId2GradeDO.get(studentDO.getGradeId()) != null ? gradeId2GradeDO.get(studentDO.getGradeId()).getTitle() : "")
                .build()
        ).toList();

    }

    @Override
    public void addStudent(AddStudentReqVO addStudentReqVO) {
        String name = addStudentReqVO.getName();
        Integer classId = addStudentReqVO.getClassId();
        Integer gradeId = addStudentReqVO.getGradeId();
        LocalDateTime createTime = addStudentReqVO.getCreateTime();
        StudentDO studentDO = StudentDO.builder()
                .name(name)
                .classId(classId)
                .gradeId(gradeId)
                .actualGradeId(gradeId)
                .startTime(createTime)
                .build();
        studentDOMapper.insert(studentDO);

        List<Integer> integers = vocabularyBankMapper.selectAllIds();
        wordMasteryLogDOMapper.batchInsertInitialization(integers, studentDO.getId());
    }

    @Override
    public void deleteStudent(Integer studentId) {
        studentDOMapper.deleteById(studentId);
    }

    @Override
    public String analyzeStudentStudy(Integer studentId) {

        String key = StudentConstant.buildAnalyzeStudentStudyKey(studentId);
        if (redisTemplate.hasKey(key)) {
            Object ans = redisTemplate.opsForValue().get(key);
            return JsonUtils.toJsonString(ans);
        }

        List<ExamWordsJudgeResultDO> examWordsJudgeResultDOS = examWordsJudgeResultDOMapper.selectByStudentIdAndLimitTime(studentId);

        List<Integer> wordIds = new java.util.ArrayList<>(examWordsJudgeResultDOS.stream().map(ExamWordsJudgeResultDO::getCorrectWordIds).flatMap(List::stream).toList());
        wordIds.addAll(examWordsJudgeResultDOS.stream().map(ExamWordsJudgeResultDO::getWrongWordIds).flatMap(List::stream).toList());
        List<VocabularyBankDO> vocabularyBankDOS = new ArrayList<>();
        if (!wordIds.isEmpty()) {
            vocabularyBankDOS = vocabularyBankMapper.selectVocabularyBankDOListByIds(wordIds);
        }
        Map<Integer, VocabularyBankDO> id2Word = vocabularyBankDOS.stream().collect(Collectors.toMap(VocabularyBankDO::getId, vocabularyBankDO -> vocabularyBankDO));

        List<ExamWordsJudgeResultDetail> examWordsJudgeResultDetails = new ArrayList<>();
        for (ExamWordsJudgeResultDO examWordsJudgeResultDO : examWordsJudgeResultDOS) {
            List<Integer> correctWordIds = examWordsJudgeResultDO.getCorrectWordIds();
            List<String> correctWords = correctWordIds.stream().map(id2Word::get).map(VocabularyBankDO::getWord).toList();
            List<Integer> wrongWordIds = examWordsJudgeResultDO.getWrongWordIds();
            List<String> wrongWords = wrongWordIds.stream().map(id2Word::get).map(VocabularyBankDO::getWord).toList();

            examWordsJudgeResultDetails.add(ExamWordsJudgeResultDetail.builder()
                    .correctWordCount(examWordsJudgeResultDO.getCorrectWordCount())
                    .wrongWordCount(examWordsJudgeResultDO.getWrongWordCount())
                    .startDate(examWordsJudgeResultDO.getStartDate())
                    .correctWords(correctWords)
                    .wrongWords(wrongWords)
                    .msg(examWordsJudgeResultDO.getMsg()).build()
            );
        }

        Map<String, Object> studentStudyInfo = new HashMap<>();
        studentStudyInfo.put("考试记录", examWordsJudgeResultDetails);

        List<WordMasteryLogDO> wordMasteryLogDOS = wordMasteryLogDOMapper.selectByStudentIdAndLimitTime(studentId);
        List<VocabularyBankDO> masteredWords = vocabularyBankMapper.selectVocabularyBankDOListByIds(wordMasteryLogDOS.stream().map(WordMasteryLogDO::getWordId).toList());
        Map<Integer, VocabularyBankDO> id2MasteryWord = masteredWords.stream().collect(Collectors.toMap(VocabularyBankDO::getId, vocabularyBankDO -> vocabularyBankDO));
        List<WordMasteryDetail> wordMasteryDetails = new ArrayList<>();
        for (WordMasteryLogDO wordMasteryLogDO : wordMasteryLogDOS) {
            wordMasteryDetails.add(WordMasteryDetail.builder()
                    .word(id2MasteryWord.get(wordMasteryLogDO.getWordId()).getWord())
                    .reviewCount(wordMasteryLogDO.getReviewCount())
                    .memoryStrength(wordMasteryLogDO.getMemoryStrength())
                    .update_time(wordMasteryLogDO.getUpdate_time())
                    .build());
        }
        studentStudyInfo.put("单词掌握情况", wordMasteryDetails);

        try {
            String analyze = difyClient.sendStudentAnalyze(JsonUtils.toJsonString(studentStudyInfo)).getAnswer();
            // 设置过期时间 3 天
            redisTemplate.opsForValue().set(key, analyze);
            redisTemplate.expire(key, 3, TimeUnit.DAYS);

            studentStageLearningRemarkDOMapper.insert(StudentStageLearningRemarkDO.builder()
                    .studentId(studentId)
                    .commentContent(analyze)
                    .createTime(LocalDateTime.now())
                    .build());

            return analyze;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public List<WordMasteryDetail> findStudentWordMasteryDetail(Integer studentId) {

        List<WordMasteryLogDO> wordMasteryLogDOS = wordMasteryLogDOMapper.selectAllByStudentId(studentId);
        List<VocabularyBankDO> masteredWords = vocabularyBankMapper.selectVocabularyBankDOListByIds(wordMasteryLogDOS.stream().map(WordMasteryLogDO::getWordId).toList());
        Map<Integer, VocabularyBankDO> id2MasteryWord = masteredWords.stream().collect(Collectors.toMap(VocabularyBankDO::getId, vocabularyBankDO -> vocabularyBankDO));
        List<WordMasteryDetail> wordMasteryDetails = new ArrayList<>();
        for (WordMasteryLogDO wordMasteryLogDO : wordMasteryLogDOS) {
            wordMasteryDetails.add(WordMasteryDetail.builder()
                    .word(id2MasteryWord.get(wordMasteryLogDO.getWordId()).getWord())
                    .reviewCount(wordMasteryLogDO.getReviewCount())
                    .memoryStrength(wordMasteryLogDO.getMemoryStrength())
                    .update_time(wordMasteryLogDO.getUpdate_time())
                    .build());
        }
        return wordMasteryDetails;
    }
}
