package com.cxy.classroll.student.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cxy.classroll.model.entity.Lesson;
import com.cxy.classroll.model.entity.Stu_lesson;
import com.cxy.classroll.model.entity.User;
import com.cxy.classroll.model.form.AuthenticationForm;
import com.cxy.classroll.model.vo.IdentifyAndID;
import com.cxy.classroll.student.mapper.LessonInfoMapper;
import com.cxy.classroll.student.mapper.StuLessonMapper;
import com.cxy.classroll.student.mapper.UserMapper;
import com.cxy.classroll.student.service.CommonService;
import com.cxy.classroll.student.service.LessonInfoService;
import com.cxy.classroll.student.service.StuLessonService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CommonServiceImpl extends ServiceImpl<UserMapper, User> implements CommonService {

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LessonInfoService lessonInfoService;

    @Autowired
    private StuLessonMapper stuLessonMapper;

    @Autowired
    private LessonInfoMapper lessonInfoMapper;

    @Override
    public IdentifyAndID login(String code) {
        IdentifyAndID identifyAndID = new IdentifyAndID();
        String openid = null;
        try {
            WxMaJscode2SessionResult sessionInfo =
                    wxMaService.getUserService().getSessionInfo(code);
            openid = sessionInfo.getOpenid();
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }

        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getWx_open_id,openid);
        User user = userMapper.selectOne(wrapper);

        if (user == null){
            user = new User();
            user.setWx_open_id(openid);
            user.setIdentify(0);
            user.setScore(0);
            userMapper.insert(user);

            identifyAndID.setId(user.getId());
            identifyAndID.setIdentify(0);
            return identifyAndID;
        }
        identifyAndID.setId(user.getId());
        identifyAndID.setIdentify(user.getIdentify());
        return identifyAndID;

    }

    @Override
    public Boolean authentication(AuthenticationForm authenticationForm) {
        Long id = authenticationForm.getId();
        User user = userMapper.selectById(id);
        if (user == null){
            return false;
        }
        user.setIdentify(authenticationForm.getIdentify());
        user.setNo(authenticationForm.getNo());
        user.setName(authenticationForm.getName());
        user.setSchool(authenticationForm.getSchool());
        user.setScore(1);
        userMapper.updateById(user);
        return true;
    }

    @Override
    public User getUserInfo(Long id) {
        User user = userMapper.selectById(id);
        return user;
    }

    @Override
    public Boolean updateUserScore(Long id, int scoreChange) {
        User user = userMapper.selectById(id);
        int score = user.getScore();
        score += scoreChange;
        user.setScore(score);
        int i = userMapper.updateById(user);
        if (i == 0){
            return false;
        }
        return true;
    }

    @Override
    public Boolean studentSignInClass(Long user_id, Long lesson_id) {
        Integer status = lessonInfoService.listenLessonStatus(lesson_id);
        if (status == 0){
            return false;
        }
        Boolean updateRes = updateUserScore(user_id, 1);
        if (!updateRes){
            return false;
        }
        return true;
    }

    @Override
    public Boolean studentSignOutClass(Long user_id, Long lesson_id) {
        Integer status = lessonInfoService.listenLessonStatus(lesson_id);
        if (status == 1 ){
            return false;
        }
        return true;
    }

    @Override
    public String classroll(Long lesson_id, int roll_method) {
        List<User> students = new ArrayList<>();
        Lesson lesson = lessonInfoService.getLessonInfoById(lesson_id);
        LambdaQueryWrapper<Stu_lesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Stu_lesson::getLesson_name, lesson.getLesson_name());
        List<Stu_lesson> stuLessonListByLessonName = stuLessonMapper.selectList(queryWrapper);
        for(Stu_lesson stuLesson:stuLessonListByLessonName){
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getNo, stuLesson.getStudent_no());
            User user = userMapper.selectOne(wrapper);
            if (user == null){
                continue;
            }
            students.add(user);
        }
        if (roll_method == 1){
            double totalWeight = students.stream().mapToDouble(student -> 1.0 / student.getScore()).sum();
            Random random = new Random();
            double randomWeight = random.nextDouble();
            double cumulativeWeight = 0.0;
            for (User student : students) {
                cumulativeWeight += (1.0 / student.getScore()) / totalWeight;
                if (randomWeight < cumulativeWeight) {
                    LambdaUpdateWrapper<Lesson> updateWrapper = new LambdaUpdateWrapper<>();
                    updateWrapper.eq(Lesson::getId,lesson.getId()).set(Lesson::getRoll,student.getNo());
                    lessonInfoMapper.update(null,updateWrapper);
                    return student.getNo();
                }
            }
            return null;
        }
        if (roll_method == 2){
            LocalDate today = LocalDate.now();
            boolean isOddDay = today.getDayOfMonth() % 2 != 0;

            // 根据日期的奇偶性调整权重
            List<User> weightedStudents = students.stream()
                    .flatMap(student -> {
                        boolean isOddId = Integer.parseInt(student.getNo().trim()) % 2 != 0;
                        int weight = (isOddDay == isOddId) ? 3 : 1; // 奇数日奇数学生权重为3，偶数学生权重为1
                        return java.util.stream.Stream.generate(() -> student).limit(weight);
                    }).collect(Collectors.toList());

            // 从加权后的学生列表中随机选择一个学生
            Random random = new Random();
            int randomIndex = random.nextInt(weightedStudents.size());
            LambdaUpdateWrapper<Lesson> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Lesson::getId,lesson.getId()).set(Lesson::getRoll,Integer.parseInt(weightedStudents.get(randomIndex).getNo()));
            lessonInfoMapper.update(null,updateWrapper);
            return weightedStudents.get(randomIndex).getNo();
        }
        return null;
    }

    @Override
    public List<User> scoreRank() {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getIdentify,1);
        wrapper.orderByDesc(User::getScore);
        return userMapper.selectList(wrapper);
    }

    @Override
    public Boolean teacherComment(Long lesson_id, String student_no, int score) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getNo, student_no);
        User user = userMapper.selectOne(wrapper);
        if (user == null){
            return false;
        }
        int score1 = user.getScore();
        score1 += score;
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(User::getScore,score1)
                .eq(User::getNo, student_no);
        int update = userMapper.update(null, updateWrapper);
        if (update == 0){
            return false;
        }
        LambdaUpdateWrapper<Lesson> lessonUpdateWrapper = new LambdaUpdateWrapper<>();
        lessonUpdateWrapper.set(Lesson::getRoll, 0)
                .eq(Lesson::getId, lesson_id);
        int updateLessonRoll = lessonInfoMapper.update(null, lessonUpdateWrapper);
        if (updateLessonRoll == 0){
            return false;
        }
        return true;
    }

    @Override
    public List<String> leesonStudentNoList(Long lesson_id) {
        List<String> studentNoList = new ArrayList<>();
        Lesson lesson = lessonInfoService.getLessonInfoById(lesson_id);
        LambdaQueryWrapper<Stu_lesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Stu_lesson::getLesson_name, lesson.getLesson_name());
        List<Stu_lesson> stuLessonListByLessonName = stuLessonMapper.selectList(queryWrapper);
        for(Stu_lesson stuLesson:stuLessonListByLessonName){
            studentNoList.add(stuLesson.getStudent_no());
        }
        return studentNoList;
    }
}
