package com.yonge.cooleshow.biz.dal.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.yonge.cooleshow.biz.dal.dao.ActivityEvaluationRecordDao;
import com.yonge.cooleshow.biz.dal.dao.ActivityPlanDao;
import com.yonge.cooleshow.biz.dal.dao.StudentDao;
import com.yonge.cooleshow.biz.dal.dto.search.ActivityEvaluationRecordSearch;
import com.yonge.cooleshow.biz.dal.entity.ActivityEvaluation;
import com.yonge.cooleshow.biz.dal.entity.ActivityEvaluationRecord;
import com.yonge.cooleshow.biz.dal.entity.ActivityPlan;
import com.yonge.cooleshow.biz.dal.entity.MusicSheet;
import com.yonge.cooleshow.biz.dal.entity.Student;
import com.yonge.cooleshow.biz.dal.entity.Subject;
import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationRecordService;
import com.yonge.cooleshow.biz.dal.service.ActivityEvaluationService;
import com.yonge.cooleshow.biz.dal.service.ActivityPlanService;
import com.yonge.cooleshow.biz.dal.service.MusicSheetService;
import com.yonge.cooleshow.biz.dal.service.SubjectService;
import com.yonge.cooleshow.biz.dal.vo.ActivityEvaluationRecordVo;
import com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo;
import com.yonge.cooleshow.common.enums.ActivityResourceEnum;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.base.util.ThreadPool;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ActivityEvaluationRecordServiceImpl extends ServiceImpl<ActivityEvaluationRecordDao, ActivityEvaluationRecord> implements ActivityEvaluationRecordService {

    @Autowired
    private ActivityEvaluationService activityEvaluationService;
    @Autowired
    private ActivityEvaluationRecordService activityEvaluationRecordService;
    @Autowired
    private ActivityPlanService activityPlanService;
    @Autowired
    private MusicSheetService musicSheetService;
    @Autowired
    private ActivityPlanDao activityPlanMapper;
    @Autowired
    private StudentDao studentMapper;
    @Autowired
    private SubjectService subjectService;

	@Override
    public ActivityEvaluationRecordVo detail(Long id) {
        return baseMapper.detail(id);
    }
    
    @Override
    public IPage<ActivityEvaluationRecordVo> selectPage(IPage<ActivityEvaluationRecordVo> page, ActivityEvaluationRecordSearch query){
        return page.setRecords(baseMapper.selectPage(page, query));
    }

    @Override
    public List<Long> getJoinEvaluationIdList(Long activityId, Long userId) {
        return baseMapper.getJoinEvaluationIdList(activityId,userId);
    }

    @Override
    public void saveRecord(Long evaluationId, Long userId, BigDecimal score) {
        if (evaluationId == null) {
            throw new BizException("评测项目id不能为空");
        }
        ActivityEvaluation activityEvaluation = activityEvaluationService.getById(evaluationId);
        if (activityEvaluation == null) {
            throw new BizException("未找到评测项目");
        }

        // 记录曲目评测试分数
        ActivityEvaluationRecord activityEvaluationRecord = new ActivityEvaluationRecord();
        activityEvaluationRecord.setActivityId(activityEvaluation.getActivityId());
        activityEvaluationRecord.setUserId(userId);
        activityEvaluationRecord.setEvaluationId(evaluationId);
        activityEvaluationRecord.setResourceId(activityEvaluation.getMusicSheetId());
        activityEvaluationRecord.setCreateTime(new Date());
        activityEvaluationRecord.setScore(score == null ? 0:score.doubleValue());
        
        ActivityEvaluationRecord lastestRecord = baseMapper.queryLastestRecord(activityEvaluation.getActivityId(), userId);
        if(lastestRecord == null){
        	activityEvaluationRecord.setTimes(1);
        }else{
        	activityEvaluationRecord.setTimes(lastestRecord.getTimes() + 1);
        }
        save(activityEvaluationRecord);

        // 活动信息
        ActivityPlan activity = activityPlanService.getById(activityEvaluation.getActivityId());
        if (ActivityRankingMethodEnum.TOTAL_SCORE == activity.getRankingMethod()) {

            // 若为总分评测，计算声部分数
            ThreadPool.getExecutor().submit(() -> {

                List<ActivityEvaluationRecord> records = activityEvaluationRecordService.list(Wrappers.<ActivityEvaluationRecord>lambdaQuery()
                        .eq(ActivityEvaluationRecord::getActivityId, activityEvaluation.getActivityId())
                        .eq(ActivityEvaluationRecord::getUserId, userId));

                // 用户当前声部所有评测数据，获取单曲最高进行加和计算为声部最高分
                Map<Long, Double> highestScoreMap = records.stream()
                        .filter(x -> Optional.ofNullable(x.getScore()).orElse(0D) > 0)
                        .filter(x -> Optional.ofNullable(x.getEvaluationId()).orElse(0L) > 0)
                        .collect(Collectors.groupingBy(ActivityEvaluationRecord::getEvaluationId,
                                Collectors.mapping(ActivityEvaluationRecord::getScore, Collectors.toSet())))
                        .entrySet().stream()
                        .collect(Collectors.toMap(Map.Entry::getKey,
                                x -> x.getValue().stream().mapToDouble(Double::doubleValue).max().orElse(0D), (o, n) -> n));

                // 最高分
                double sumScore = highestScoreMap.values().stream().mapToDouble(Double::doubleValue).sum();

                // 获取最高分的时间为每个单曲最高分的记录时间
                Map<Long, Long> highestScoreTimeMap = records.stream()
                        .filter(x -> Optional.ofNullable(x.getScore()).orElse(0D) > 0)
                        .filter(x -> Optional.ofNullable(x.getEvaluationId()).orElse(0L) > 0)
                        .filter(x -> highestScoreMap.getOrDefault(x.getEvaluationId(), -1D).doubleValue() == x.getScore())
                        .collect(Collectors.groupingBy(ActivityEvaluationRecord::getEvaluationId, Collectors.mapping(x -> x.getCreateTime().getTime(), Collectors.toSet())))
                        .entrySet().stream()
                        .collect(Collectors.toMap(Map.Entry::getKey,
                                x -> x.getValue().stream().mapToLong(Long::longValue).max().orElse(0L), (o, n) -> n));

                // 最高分时间
                long highScoreTime = highestScoreTimeMap.values().stream().mapToLong(Long::longValue).max().orElse(DateTime.now().getMillis());

                // 若分总相同，最高分时间相同，则根据用户活动报名时间进行排序
                Date registrationTime = records.stream()
                        .filter(x -> Objects.isNull(x.getScore()))
                        .min(Comparator.comparing(ActivityEvaluationRecord::getId))
                        .map(ActivityEvaluationRecord::getCreateTime).orElse(DateTime.now().toDate());

                // 查询用户声部评分记录
                ActivityEvaluationRecord evaluationRecord = activityEvaluationRecordService.getOne(Wrappers.<ActivityEvaluationRecord>lambdaQuery()
                        .eq(ActivityEvaluationRecord::getActivityId, activity.getId())
                        .eq(ActivityEvaluationRecord::getUserId, userId)
                        .eq(ActivityEvaluationRecord::getRankingMethod, activity.getRankingMethod())
                );

                if (Objects.isNull(evaluationRecord)) {

                    MusicSheet musicSheet = musicSheetService.getById(activityEvaluation.getMusicSheetId());

                    long subjectId = 0;
                    if (Objects.nonNull(musicSheet)) {
                        subjectId = Long.parseLong(musicSheet.getMusicSubject().split(",")[0]);
                    }
                    // 添加用户声部总分记录
                    ActivityEvaluationRecord record = new ActivityEvaluationRecord();

                    record.setActivityId(activityEvaluation.getActivityId());
                    record.setUserId(userId);
                    record.setEvaluationId(0L);
                    // 声部ID
                    record.setResourceId(subjectId);
                    record.setRegistrationTime(registrationTime.getTime());
                    record.setRankingMethod(activity.getRankingMethod());
                    record.setTimes(0);
                    // 最高分时间
                    record.setCreateTime(new DateTime(highScoreTime).toDate());
                    record.setScore(sumScore);

                    save(record);
                }

                // 更新最高分记录
                if (Objects.nonNull(evaluationRecord)
                        && evaluationRecord.getScore() < sumScore) {

                    ActivityEvaluationRecord record = new ActivityEvaluationRecord();

                    record.setId(evaluationRecord.getId());
                    record.setScore(sumScore);
                    record.setCreateTime(new DateTime(highScoreTime).toDate());

                    updateById(record);
                }

            });
        }

    }


    @Override
    public void saveActivityRecord(Long activityId, Long userId, Long resourceId, ActivityResourceEnum resourceType) {
        List<ActivityEvaluation> list = activityEvaluationService.lambdaQuery()
                                                                 .eq(ActivityEvaluation::getActivityId, activityId)
                                                                 .eq(ActivityEvaluation::getMusicSheetId, resourceId)
                                                                 .eq(ActivityEvaluation::getResourceType, resourceType)
                                                                 .list();
        ActivityEvaluation activityEvaluation = new ActivityEvaluation();
        if (!CollectionUtils.isEmpty(list)) {
            activityEvaluation = list.get(0);
        }
        ActivityEvaluationRecord activityEvaluationRecord = new ActivityEvaluationRecord();
        activityEvaluationRecord.setResourceId(resourceId);
        activityEvaluationRecord.setUserId(userId);
        activityEvaluationRecord.setActivityId(activityId);
        activityEvaluationRecord.setEvaluationId(activityEvaluation.getId());
        this.save(activityEvaluationRecord);
    }

    @Override
	public List<ActivityRankingVo> queryRankingList(Long activityPlanId, Long activityEvaluationId, int limit) {
        ActivityPlan activityPlan = activityPlanService.getById(activityPlanId);
        if (activityPlan == null) {
            throw new BizException("活动已结束");
        }

        List<ActivityRankingVo> activityRankings;
        // 活动排名
        if (ActivityRankingMethodEnum.TOTAL_SCORE == activityPlan.getRankingMethod()) {

            // 总分排名, 根据声部ID进行查询
            activityRankings = activityPlanMapper.selectActivityHighestScoreRankingInfo(activityPlanId, activityEvaluationId,
                    1D, limit);

            List<Long> userIds = activityRankings.stream()
                    .map(ActivityRankingVo::getUserId).distinct().collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(userIds)) {

                Map<Long, Long> userSubjectMap = studentMapper.selectList(Wrappers.<Student>lambdaQuery().in(Student::getUserId, userIds)).stream()
                        .filter(x -> Objects.nonNull(x.getSubjectId()))
                        .collect(Collectors.toMap(Student::getUserId, x -> Long.parseLong(Optional.ofNullable(x.getSubjectId()).orElse("0").split(",")[0]), (o, n) -> n));


                Map<Long, String> subjectNameMap = subjectService.findBySubjectByIdList(Lists.newArrayList(userSubjectMap.values())).stream()
                        .collect(Collectors.toMap(Subject::getId, Subject::getName, (o, n) -> n));

                for (ActivityRankingVo item : activityRankings) {

                    item.setUserSubject(subjectNameMap.getOrDefault(userSubjectMap.get(item.getUserId()), ""));
                }
            }

        } else {

            // 单曲排名
            activityRankings = baseMapper.queryRankingList(activityPlanId, activityEvaluationId, limit, activityPlan.getRankingRule());
        }

        return activityRankings;
	}

	@Override
	public ActivityRankingVo queryUserRanking(Long activityPlanId, Long activityEvaluationId, Long userId) {
        ActivityPlan activityPlan = activityPlanService.getById(activityPlanId);
        if (activityPlan == null) {
            throw new BizException("活动已结束");
        }

        // 用户排名信息
        ActivityRankingVo userRanking;

        if (ActivityRankingMethodEnum.TOTAL_SCORE == activityPlan.getRankingMethod()) {

            // 总分排名
            userRanking = activityPlanMapper.selectActivityHighestScoreUserRanking(activityPlanId, activityEvaluationId,
                    1D, userId);

            // 学生声部信息
            Student student = studentMapper.selectOne(Wrappers.<Student>lambdaQuery().eq(Student::getUserId, userId));

            String userSubject = "";
            if (Objects.nonNull(student) && Objects.nonNull(student.getSubjectId())) {
                long subjectId = Long.parseLong(student.getSubjectId().split(",")[0]);

                Subject subject = subjectService.get(subjectId);

                // 学生声部信息
                userSubject = Optional.ofNullable(subject).map(Subject::getName).orElse("");
            }

            if (Objects.nonNull(userRanking)) {

                userRanking.setUserSubject(userSubject);
            }

        } else {

            // 单曲排名
            userRanking = baseMapper.queryUserRanking(activityPlanId, activityEvaluationId, userId, activityPlan.getRankingRule());
        }

        return userRanking;
	}

    /**
     * 用户活动最高排名信息
     *
     * @param activityId 活动ID
     * @param userIds 用户ID
     * @return List<ActivityEvaluationRecord>
     */
    @Override
    public List<ActivityEvaluationRecord> queryActivityUserHighestRankingInfo(Long activityId, List<Long> userIds) {

        if (CollectionUtils.isEmpty(userIds)) {
            return Lists.newArrayList();
        }
        ActivityPlan activityPlan = activityPlanService.getById(activityId);
        if (activityPlan == null) {
            throw new BizException("活动已结束");
        }
        // 用户最高排名信息
        List<ActivityEvaluationRecord> records = getBaseMapper().selectUserHighestRankingInfo(activityId, userIds,activityPlan.getRankingRule());

        return Optional.ofNullable(records).orElse(Lists.newArrayList());
    }

}