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

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
import com.yonge.cooleshow.auth.api.entity.SysUser;
import com.yonge.cooleshow.biz.dal.dao.ActivityPlanDao;
import com.yonge.cooleshow.biz.dal.dao.StudentDao;
import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
import com.yonge.cooleshow.biz.dal.dto.ActivityPlanDto;
import com.yonge.cooleshow.biz.dal.dto.ActivityPlanPayDto;
import com.yonge.cooleshow.biz.dal.dto.ActivityPlanRewardDto;
import com.yonge.cooleshow.biz.dal.dto.SaveOrUpdateRewardDto;
import com.yonge.cooleshow.biz.dal.dto.activity.ActivityTeacherQuery;
import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
import com.yonge.cooleshow.biz.dal.dto.search.ActivityPlanSearch;
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.ActivityPlanReward;
import com.yonge.cooleshow.biz.dal.entity.ActivityRegistration;
import com.yonge.cooleshow.biz.dal.entity.ActivityReward;
import com.yonge.cooleshow.biz.dal.entity.Student;
import com.yonge.cooleshow.biz.dal.entity.Subject;
import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
import com.yonge.cooleshow.biz.dal.enums.EQueryOp;
import com.yonge.cooleshow.biz.dal.enums.MK;
import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
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.ActivityPlanEvaluationService;
import com.yonge.cooleshow.biz.dal.service.ActivityPlanRewardService;
import com.yonge.cooleshow.biz.dal.service.ActivityPlanService;
import com.yonge.cooleshow.biz.dal.service.ActivityPlanStandardService;
import com.yonge.cooleshow.biz.dal.service.ActivityRegistrationService;
import com.yonge.cooleshow.biz.dal.service.ActivityRewardService;
import com.yonge.cooleshow.biz.dal.service.SubjectService;
import com.yonge.cooleshow.biz.dal.service.SysMessageService;
import com.yonge.cooleshow.biz.dal.vo.ActivityMusicVo;
import com.yonge.cooleshow.biz.dal.vo.ActivityPlanVo;
import com.yonge.cooleshow.biz.dal.vo.ActivityRankingVo;
import com.yonge.cooleshow.biz.dal.vo.MusicActivityVo;
import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
import com.yonge.cooleshow.biz.dal.vo.activity.ActivityTeacherWrapper;
import com.yonge.cooleshow.biz.dal.vo.res.OrderCreateRes;
import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.cooleshow.common.enums.ActivityResourceEnum;
import com.yonge.cooleshow.common.enums.ActivityShareEnum;
import com.yonge.cooleshow.common.enums.ActivityTypeEnum;
import com.yonge.cooleshow.common.enums.CacheNameEnum;
import com.yonge.cooleshow.common.enums.EStatus;
import com.yonge.cooleshow.common.enums.RegistrationMethodEnum;
import com.yonge.cooleshow.common.enums.YesOrNoEnum;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.base.util.StringUtil;
import com.yonge.toolset.base.util.ThreadPool;
import com.yonge.toolset.payment.util.DistributedLock;
import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;


@Service
public class ActivityPlanServiceImpl extends ServiceImpl<ActivityPlanDao, ActivityPlan> implements ActivityPlanService {
    private final static Logger log = LoggerFactory.getLogger(ActivityPlanServiceImpl.class);
    @Autowired
    private ActivityPlanEvaluationService activityPlanEvaluationService;

    @Autowired
    private ActivityPlanStandardService activityPlanStandardService;

    @Autowired
    private ActivityEvaluationService activityEvaluationService;

    @Autowired
    private ActivityPlanRewardService activityPlanRewardService;

    @Autowired
    private ActivityPlanDao activityPlanDao;

    @Autowired
    private ActivityRewardService activityRewardService;

    @Resource
    private SysUserFeignService sysUserFeignService;

    @Autowired
    private ActivityRegistrationService activityRegistrationService;

    @Autowired
    private ActivityEvaluationRecordService activityEvaluationRecordService;

    @Autowired
    private SysMessageService sysMessageService;

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private StudentDao studentMapper;
    @Autowired
    private SubjectService subjectService;

    //保存/更新拓展字段
    private static final Map<ActivityTypeEnum, Consumer<ActivityPlanDto>> saveOrUpdateExpand = new HashMap<>();
    //开始活动（活动刚开始触发）
    private static final Map<ActivityTypeEnum, Consumer<Long>> startActivity = new HashMap<>();
    //开启活动（开启活动按钮）
    private static final Map<ActivityTypeEnum, Consumer<Long>> openActivity = new HashMap<>();
    //关闭活动（关闭活动按钮）
    private static final Map<ActivityTypeEnum, Consumer<Long>> closeActivity = new HashMap<>();
    //活动中定时轮询
    private static final Map<ActivityTypeEnum, Consumer<Object>> activityIng = new HashMap<>();
    //活动完成（活动截止时间到触发）
    private static final Map<ActivityTypeEnum, Consumer<Long>> successActivity = new HashMap<>();

    @PostConstruct
    private void init() {
        /**********保存/更新拓展字段******************/
        //评测活动
        saveOrUpdateExpand.put(ActivityTypeEnum.EVALUATION, activityPlanEvaluationService::createOrUpdate);
        //达标赠送活动
        saveOrUpdateExpand.put(ActivityTypeEnum.STANDARD_GIFT, activityPlanStandardService::createOrUpdate);
        /**********开始活动（活动刚开始触发）******************/

        /**********开启活动（开启活动按钮）******************/

        /**********关闭活动（关闭活动按钮）******************/
        //评测活动
        closeActivity.put(ActivityTypeEnum.EVALUATION, activityPlanEvaluationService::closeActivity);
        /**********活动中定时轮询******************/
        //达标赠送活动
        activityIng.put(ActivityTypeEnum.STANDARD_GIFT, activityPlanStandardService::activityIng);
        /**********活动完成（活动截止时间到触发）******************/
        //评测活动
        successActivity.put(ActivityTypeEnum.EVALUATION, activityPlanEvaluationService::successActivity);
        //达标赠送活动
        successActivity.put(ActivityTypeEnum.STANDARD_GIFT, activityPlanStandardService::successActivity);
    }

    @Override
    public ActivityPlanVo detail(Long id) {
        if (id == null) {
            return null;
        }
        ActivityPlanVo detail = baseMapper.detail(id);
        if (null != detail) {
            if (ActivityTypeEnum.EVALUATION.equals(detail.getActivityType())) {
                detail.setPlanEvaluation(activityPlanEvaluationService.getById(id));
            }
            if (ActivityTypeEnum.STANDARD_GIFT.equals(detail.getActivityType())) {
                detail.setPlanStandard(activityPlanStandardService.getById(id));
            }
        } else {
            return null;
        }
        //查询活动奖品
        List<ActivityPlanRewardDto> activityRewardList = activityPlanRewardService.queryActivityPlanReward(id);
        detail.setActivityRewardList(activityRewardList);
        return detail;
    }

    @Override
    public IPage<ActivityPlanVo> selectPage(IPage<ActivityPlanVo> page, ActivityPlanSearch query) {

        List<ActivityPlanVo> wrappers = baseMapper.selectPage(page, query);

        if (CollectionUtils.isEmpty(wrappers)) {
            return page.setRecords(wrappers);
        }

        List<Long> activityIds = wrappers.stream()
                .map(ActivityPlan::getId).distinct().collect(Collectors.toList());

        // 参与人数
        Map<Long, Integer> participantNumMap = Maps.newConcurrentMap();
        // 获奖人数
        Map<Long, Integer> winnerNumMap = Maps.newConcurrentMap();
        Lists.partition(activityIds, 30).parallelStream().forEach(item ->

            Lists.newArrayList(EQueryOp.values()).parallelStream().forEach(dataType -> {

                switch (dataType) {
                    case FUNCTION_1:
                        // 参与人数
                        Map<Long, Integer> participantMap = getBaseMapper().selectActivityParticipateStatInfo(activityIds).stream()
                                .collect(Collectors.toMap(StatGroupWrapper::getId, StatGroupWrapper::getTotal, (o, n) -> n));

                        participantNumMap.putAll(participantMap);
                        break;
                    case FUNCTION_2:
                        // 获奖人数
                        Map<Long, Integer> winnerMap = getBaseMapper().selectActivityWinnerStatInfo(activityIds).stream()
                                .collect(Collectors.toMap(StatGroupWrapper::getId, StatGroupWrapper::getTotal, (o, n) -> n));

                        winnerNumMap.putAll(winnerMap);
                        break;
                    default:
                        break;
                }

            })
        );

        // 分享活动-参与人数获奖人数相等
        for (ActivityPlanVo item : wrappers) {

            // 参与人数、获奖人数
            item.registrationNum(participantNumMap.getOrDefault(item.getId(), 0))
                    .rewardNum(winnerNumMap.getOrDefault(item.getId(), 0));

            // 重置分享活动获奖与参与人数
            if (ActivityTypeEnum.SHARE == item.getActivityType()) {
                item.setRegistrationNum(item.getRewardNum());
            }
        }

        return page.setRecords(wrappers);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ActivityPlan submit(ActivityPlanDto activityPlan) {
        //验证参数
        if (!validParam(activityPlan)) {
            throw new BizException("参数异常");
        }

        // 活动ID
        long activityId;
        if (null == activityPlan.getId()) {
            activityPlan.setDraftFlag(1);
            activityPlan.setCreateBy(activityPlan.getUserId());
            activityPlan.setUpdateBy(activityPlan.getUserId());
            save(activityPlan);

            // 更新分享活动奖品信息
            activityId = activityPlan.getId();
        } else {
            ActivityPlan old = getById(activityPlan.getId());

            // 分享活动-活动时间修改需要先校验与老师其他分享活动是否存在冲突
            if (ActivityTypeEnum.SHARE == old.getActivityType()) {

                validActivityTeacherDuplicatTimeParam(activityPlan, old);
            }

            //启用状态，只能修改活动结束时间
            if (old.getActivityState().equals(1)) {
                if (activityPlan.getActivityEnd().after(new Date())) {
                    old.setActivityEnd(activityPlan.getActivityEnd());
                    old.setUpdateBy(activityPlan.getUserId());
                    updateById(old);
                }
            } else {
                activityPlan.setUpdateBy(activityPlan.getUserId());
                updateById(activityPlan);
            }

            // 更新活动ID
            activityId = old.getId();
        }

        // 分享活动-奖品信息
        if (CollectionUtils.isNotEmpty(activityPlan.getRewardItems())) {

            insertActivityRewardSelectiveInfo(activityPlan, activityId);
        }

        //修改拓展信息
        Consumer<ActivityPlanDto> afterFunction = saveOrUpdateExpand.get(activityPlan.getActivityType());
        if (!Objects.isNull(afterFunction)) {
            afterFunction.accept(activityPlan);
        }
        return activityPlan;
    }

    /**
     * 校验活动时间，添加老师是否重复
     * @param activityPlan 更新数据
     * @param old 原始数据
     */
    private void validActivityTeacherDuplicatTimeParam(ActivityPlanDto activityPlan, ActivityPlan old) {

        if (activityPlan.getActivityStart().getTime() != old.getActivityStart().getTime()
                || activityPlan.getActivityEnd().getTime() != old.getActivityEnd().getTime()) {

            // 排除当前活动，其他活动时间存在重复
            ActivityTeacherQuery query = ActivityTeacherQuery.builder()
                    .activityId(activityPlan.getId())
                    .activityType(ActivityTypeEnum.SHARE.getCode())
                    .resourceType(ActivityResourceEnum.TEACHER.getCode())
                    .activityState(EStatus.ENABLE.getValue())
                    .startTime(Optional.ofNullable(activityPlan.getActivityStart()).map(x -> x.getTime() / 1000).orElse(null))
                    .endTime(Optional.ofNullable(activityPlan.getActivityEnd()).map(x -> x.getTime() / 1000).orElse(null))
                    .build();

            // 分页查询条件
            IPage<ActivityTeacherWrapper> page = new Page<>(1, 1000);

            IPage<ActivityTeacherWrapper> wrapper = activityEvaluationService.activityTeacherByTimePageInfo(page, query);

            if (CollectionUtils.isNotEmpty(wrapper.getRecords())) {

                String collect = wrapper.getRecords().stream().map(x -> {
                    if (StringUtils.isNotEmpty(x.getUsername())) {
                        return x.getUsername();
                    }
                    return x.getRealName();
                }).distinct().collect(Collectors.joining("、"));

                throw new BizException("以下老师存在时间冲突:" + collect);
            }

        }
    }

    /**
     * 分享活动奖品信息
     * @param activityPlan ActivityPlanDto
     * @param activityId 活动ID
     */
    private void insertActivityRewardSelectiveInfo(ActivityPlanDto activityPlan, long activityId) {

        for (ActivityPlanDto.RewardItem item : activityPlan.getRewardItems()) {
            // 更新活动ID
            item.setActivityId(activityId);
        }

        List<Long> deleteRewardIds = activityPlanRewardService.getBaseMapper()
                .selectList(Wrappers.<ActivityPlanReward>lambdaQuery().eq(ActivityPlanReward::getActivityId, activityId)).stream()
                .map(ActivityPlanReward::getRewardId).distinct().collect(Collectors.toList());

        // 删除原始活动奖品映射关系
        activityPlanRewardService.getBaseMapper().delete(Wrappers.<ActivityPlanReward>lambdaQuery().eq(ActivityPlanReward::getActivityId, activityId));

        // 删除原始活动奖品信息
        if (CollectionUtils.isNotEmpty(deleteRewardIds)) {

            activityRewardService.getBaseMapper().deleteBatchIds(deleteRewardIds);
        }

        // 重新插入奖品信息
        List<ActivityReward> rewards = JSON.parseArray(JSON.toJSONString(activityPlan.getRewardItems()), ActivityReward.class);

        if (CollectionUtils.isNotEmpty(rewards)) {

            activityRewardService.saveBatch(rewards, 30);
        }

        // 重新插入活动奖品映射关系
        List<ActivityPlanDto.ActivityRewardRecord> records = Lists.newArrayList();

        for (ActivityReward item : rewards) {

            records.add(ActivityPlanDto.ActivityRewardRecord.builder()
                            .activityId(activityId)
                            .rewardId(item.getId())
                            .rewardNum(1)
                    .build());
        }
        if (CollectionUtils.isNotEmpty(records)) {

            activityPlanRewardService.saveBatch(JSON.parseArray(JSON.toJSONString(records), ActivityPlanReward.class), 30);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateActivityState(Long activityId, Integer activityState, Long id) {
        ActivityPlanVo detail = detail(activityId);

        ActivityPlan activityPlan = new ActivityPlan();

        if (activityState == 1) {
            Date now = new Date();
            if (detail.getActivityEnd().before(now)) {
                return false;
            }
            if (detail.getActivityStart().after(now)) {
                activityPlan.setActivityStart(now);
            }
            activityPlan.setActivityState(activityState);
            //开启活动
            Consumer<Long> afterFunction = openActivity.get(activityPlan.getActivityType());
            if (!Objects.isNull(afterFunction)) {
                afterFunction.accept(activityPlan.getId());
            }
        } else {
            activityPlan.setActivityState(2);
            //关闭活动
            Consumer<Long> afterFunction = closeActivity.get(activityPlan.getActivityType());
            if (!Objects.isNull(afterFunction)) {
                afterFunction.accept(activityPlan.getId());
            }
        }

        activityPlan.setId(activityId);
        activityPlan.setUpdateBy(id);
        activityPlan.setUpdateTime(new Date());
        baseMapper.updateById(activityPlan);
        return true;
    }

    @Override
    public Boolean updateDraftFlag(Long activityId, Integer draftFlag, Long userId) {
        ActivityPlan activityPlan = new ActivityPlan();
        activityPlan.setId(activityId);
        //更改活动状态
        activityPlan.setDraftFlag(draftFlag);
        activityPlan.setUpdateBy(userId);
        updateById(activityPlan);
        return true;
    }

    private Boolean validParam(ActivityPlanDto activityPlan) {
        if (null == activityPlan) {
            return false;
        }

        if (!ActivityTypeEnum.STANDARD_GIFT.equals(activityPlan.getActivityType())) {

            if (null == activityPlan.getRegistrationMethod()) {
                throw new BizException("报名缴费方式不能为空");
            }
            if (RegistrationMethodEnum.CHARGE.equals(activityPlan.getRegistrationMethod())
                    && (null == activityPlan.getRegistrationPrice() || BigDecimal.ZERO.compareTo(activityPlan.getRegistrationPrice()) > 0)) {
                throw new BizException("活动收费时，报名金额不能为空");
            }
            if (RegistrationMethodEnum.CHARGE.equals(activityPlan.getRegistrationMethod())
                    && (null == activityPlan.getShareRate())) {
                throw new BizException("活动收费时，分润比例不能为空");
            }
            if (StringUtil.isEmpty(activityPlan.getSubjectUrl())) {
                throw new BizException("主题图片不能为空");
            }
            if (StringUtil.isEmpty(activityPlan.getBackgroundUrl())) {
                throw new BizException("平铺背景不能为空");
            }
            if (StringUtil.isEmpty(activityPlan.getShareUrl())) {
                throw new BizException("分享图片不能为空");
            }
            if (StringUtil.isEmpty(activityPlan.getRuleDescribe())) {
                throw new BizException("活动规则不能为空");
            }
        }

        if (ActivityTypeEnum.EVALUATION.equals(activityPlan.getActivityType())) {
            activityPlan.setActivityClient(ClientEnum.STUDENT);
            if (null == activityPlan.getPlanEvaluation() || null == activityPlan.getPlanEvaluation().getEvaluationDifficulty()) {
                throw new BizException("活动类型为评测活动时，评测难度不能为空");
            }
        }

        if (ActivityTypeEnum.STANDARD_GIFT.equals(activityPlan.getActivityType())) {
            if (null == activityPlan.getPlanStandard()) {
                throw new BizException("缺少达标赠送参数");
            }
            if (StringUtil.isEmpty(activityPlan.getPlanStandard().getCondition())) {
                throw new BizException("达标条件不能为空");
            }
        }

        if (null == activityPlan.getActivityClient()) {
            throw new BizException("活动客户端不能为空");
        }
        return true;
    }


    @Override
    public MusicActivityVo getActivityInfo(Long activityPlanId, SysUser user) {
        ActivityPlan activityPlan = this.getById(activityPlanId);

        if (Objects.isNull(activityPlan)) {
            throw new BizException("无效的活动ID");
        }

        if (activityPlan.getActivityState() != 1) {
            activityPlan.setActivityState(0);
        }

        MusicActivityVo activityVo = new MusicActivityVo();
        BeanUtils.copyProperties(activityPlan, activityVo);

        Long userId = null;
        if (user != null && user.getId() != null) {
            userId = user.getId();
        }


        // 评测活动曲目信息
        if (ActivityTypeEnum.EVALUATION == activityPlan.getActivityType()) {

            // 活动曲目
            List<ActivityMusicVo> activityMusicVoList = activityEvaluationService.getActivityMusic(activityPlanId, userId);
            activityVo.setActivityMusicVoList(activityMusicVoList);

            // 评测难度
            String evaluationDifficulty = baseMapper.selectActivityPlanEvaluation(activityPlanId);
            activityVo.setEvaluationDifficulty(evaluationDifficulty);

            // 单曲排名
            if (ActivityRankingMethodEnum.MUSIC_RANKING == activityPlan.getRankingMethod()) {

                for (ActivityMusicVo item : activityVo.getActivityMusicVoList()) {

                    if (StringUtils.isEmpty(item.getEvaluationDifficulty())) {

                        item.setEvaluationDifficulty(evaluationDifficulty);
                    }
                }
            }

            // 计算评测活动声部最高分
            if (ActivityRankingMethodEnum.TOTAL_SCORE == activityPlan.getRankingMethod()) {

                Map<String, List<ActivityMusicVo>> collect = activityMusicVoList.stream()
                        .collect(Collectors.groupingBy(x -> x.getSubjectId().split(",")[0]));

                // 曲目难度
                Map<Integer, String> difficultyMap = Maps.newHashMap();
                difficultyMap.put(0, "BEGINNER");
                difficultyMap.put(1, "ADVANCED");
                difficultyMap.put(2, "PERFORMER");
                // FIXME:临时增加声部曲目难度字段
                for (Map.Entry<String, List<ActivityMusicVo>> entry : collect.entrySet()) {

                    int index = 0;
                    for (ActivityMusicVo item : entry.getValue()) {

                        if (StringUtils.isEmpty(item.getEvaluationDifficulty())) {

                            item.setEvaluationDifficulty(difficultyMap.getOrDefault(index, "PERFORMER"));
                        }

                        index += 1;
                    }
                }

                // 计算声部评测最高分
                Map<String, ActivityRankingVo> highestScoreMap = Maps.newConcurrentMap();
                collect.entrySet().parallelStream().forEach(item -> {

                    // 单声部计算用户总分排名用户信息
                    List<ActivityRankingVo> records = getBaseMapper().selectActivityHighestScoreRankingInfo(activityPlanId, Long.parseLong(item.getKey()),
                            1D, 1);

                    if (CollectionUtils.isNotEmpty(records)) {

                        highestScoreMap.put(item.getKey(), records.get(0));
                    }
                });

                // 用户学生身份声部信息
                List<Long> userIds = highestScoreMap.values().stream()
                        .map(ActivityRankingVo::getUserId).distinct().collect(Collectors.toList());

                Map<Long, Long> userSubjectMap = Maps.newHashMap();
                Map<Long, String> subjectNameMap = Maps.newHashMap();
                if (CollectionUtils.isNotEmpty(userIds)) {

                    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));


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


                List<MusicActivityVo.SubjectInfo> subjectInfos = Lists.newArrayList();
                ActivityMusicVo musicVo;
                ActivityRankingVo ranking;
                for (Map.Entry<String, List<ActivityMusicVo>> entry : collect.entrySet()) {

                    if (CollectionUtils.isEmpty(entry.getValue())) {
                        continue;
                    }

                    musicVo = entry.getValue().get(0);

                    MusicActivityVo.SubjectInfo subjectInfo = MusicActivityVo.SubjectInfo.builder()
                            .subjectId(musicVo.getSubjectId().split(",")[0])
                            .subjectName(musicVo.getMusicSubject())
                            .join(entry.getValue().stream().anyMatch(x -> x.getJoin() == YesOrNoEnum.YES) ? 1 : 0)
                            .userId(0L)
                            .username("")
                            .userAvatar("")
                            .userSubject("")
                            .score(0D)
                            .musicNums(entry.getValue().size())
                            .build();
                    subjectInfos.add(subjectInfo);

                    // 最高分记录
                    if (highestScoreMap.containsKey(entry.getKey())) {

                        ranking = highestScoreMap.get(entry.getKey());

                        subjectInfo.userId(ranking.getUserId())
                                .username(ranking.getUsername())
                                .userAvatar(ranking.getUserAvatar())
                                .userSubject(subjectNameMap.getOrDefault(userSubjectMap.get(ranking.getUserId()), ""))
                                .score(ranking.getScore());
                    }
                }

                activityVo.setSubjectInfos(subjectInfos);
            }
        }

        // 报名状态
        activityVo.setJoin(activityRegistrationService.getRegistration(userId, activityPlanId));

        // 活动奖品
        List<ActivityReward> activityRewardList = activityRewardService.getActivityReward(activityPlanId);
        activityVo.setActivityRewardList(activityRewardList);

        return activityVo;
    }

    @Override
    public HttpResponseResult<OrderCreateRes> orderCreate(OrderReq.OrderReqInfo orderReqInfo) {

        log.info("活动购买 参数 --> {}", orderReqInfo);

        // 检查用户
        getSysUser(orderReqInfo.getUserId());
        ActivityPlanPayDto activityPlanPayDto = JSON.parseObject(
                JSON.toJSONString(orderReqInfo.getBizContent()), ActivityPlanPayDto.class);

        // 检查活动购买是否已购买
        checkActivityPay(activityPlanPayDto.getActivityId());


        if (checkoutJoinActivity(activityPlanPayDto.getActivityId(), orderReqInfo.getUserId())) {
            throw new BizException("您已经参与了活动");
        }


        OrderCreateRes orderCreateRes = new OrderCreateRes();
        if (activityPlanPayDto.getActivityId() == null) {
            throw new BizException("活动id不能为空");
        }
        ActivityPlan activityPlan = getById(activityPlanPayDto.getActivityId());

        orderCreateRes.setRes(true);
        orderCreateRes.setGoodType(orderCreateRes.getGoodType());
        orderCreateRes.setBizId(activityPlanPayDto.getActivityId());
        orderCreateRes.setGoodNum(1);
        orderCreateRes.setOriginalPrice(activityPlan.getRegistrationPrice());
        orderCreateRes.setExpectPrice(activityPlan.getRegistrationPrice());
        return HttpResponseResult.succeed(orderCreateRes);
    }

    private boolean checkoutJoinActivity(Long activityId, Long userId) {
        return activityRegistrationService.lambdaQuery()
                .eq(ActivityRegistration::getActivityId, activityId)
                .eq(ActivityRegistration::getUserId, userId)
                .count() > 0;
    }

    @Override
    public void orderSuccess(UserOrderDetailVo userOrderDetailVo) {
        ActivityRegistration activityRegistration = new ActivityRegistration();
        activityRegistration.setUserId(userOrderDetailVo.getUserId());
        activityRegistration.setOrderNo(userOrderDetailVo.getOrderNo());
        activityRegistration.setSubOrderNo(userOrderDetailVo.getSubOrderNo());
        activityRegistration.setActivityId(userOrderDetailVo.getBizId());
        activityRegistration.setCreateTime(new Date());
        activityRegistrationService.save(activityRegistration);

        sendMessage(userOrderDetailVo.getGoodName(), userOrderDetailVo.getUserId());
    }

    @Override
    public Boolean joinEvaluation(Long evaluationId, SysUser user) {
        ActivityEvaluation activityEvaluation = activityEvaluationService.getById(evaluationId);
        if (activityEvaluation == null) {
            throw new BizException("未找到活动信息");
        }

        checkActivityPay(activityEvaluation.getActivityId());
        if (!checkoutJoinActivity(activityEvaluation.getActivityId(), user.getId())) {
            throw new BizException("请先报名参与");
        }

        List<Long> joinEvaluationIdList = activityEvaluationRecordService.getJoinEvaluationIdList(activityEvaluation.getActivityId(), user.getId());

        // 保存参与活动项目记录
        if (CollectionUtils.isEmpty(joinEvaluationIdList)) {
            ActivityEvaluationRecord activityEvaluationRecord = new ActivityEvaluationRecord();
            activityEvaluationRecord.setActivityId(activityEvaluation.getActivityId());
            activityEvaluationRecord.setUserId(user.getId());
            activityEvaluationRecord.setEvaluationId(evaluationId);
            activityEvaluationRecord.setCreateTime(new Date());

            return activityEvaluationRecordService.save(activityEvaluationRecord);
        }
        if (!joinEvaluationIdList.contains(evaluationId)) {
            throw new BizException("已经参与其他项目");
        }
        return true;
    }

    @Override
    public Boolean joinActivity(Long activityId, SysUser user) {
        checkActivityPay(activityId);
        ActivityPlan activityPlan = this.getById(activityId);
        if (checkoutJoinActivity(activityId, user.getId())) {
            throw new BizException("您已经报名了");
        }
        if (RegistrationMethodEnum.CHARGE.equals(activityPlan.getRegistrationMethod())) {
            throw new BizException("收费活动，请下单报名");
        }

        // 免费活动 参与时 添加报名记录
        ActivityRegistration activityRegistration = new ActivityRegistration();
        activityRegistration.setUserId(user.getId());
        activityRegistration.setOrderNo(null);
        activityRegistration.setSubOrderNo(null);
        activityRegistration.setActivityId(activityId);
        activityRegistration.setCreateTime(new Date());
        activityRegistrationService.save(activityRegistration);

        sendMessage(activityPlan.getActivityName(), user.getId());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void activityState() {

        // 方法调整为异常执行，预防HTTP接口调用返回超时响应
        ThreadPool.getExecutor().submit(() -> {

            RLock lock = redissonClient.getLock(CacheNameEnum.LOCK_EVALUATION_CRON.getCode());
            try {
                if (lock.isLocked()) {
                    log.warn("activityState {}, lockName={}", DateTime.now().toString(MK.TIME_PATTERN), lock.getName());
                    return;
                }

                // 增加达标活动计算同步标识，前一个请求未执行完时忽略后续执行请求
                lock.lock();

                List<ActivityPlan> list = baseMapper.activityState();
                for (ActivityPlan plan : list) {
                    DistributedLock.of(redissonClient)
                            .runIfLockToFunction(CacheNameEnum.LOCK_ACTIVITY_STOCK.getRedisKey(plan.getId())
                                    , (id) -> {
                                        ActivityPlan activityPlan = getById(id);
                                        if (activityPlan.getActivityState() == 0) {
                                            activityPlan.setActivityState(1);
                                            baseMapper.updateById(activityPlan);

                                            //开始活动
                                            Consumer<Long> afterFunction = startActivity.get(activityPlan.getActivityType());
                                            if (!Objects.isNull(afterFunction)) {
                                                afterFunction.accept(activityPlan.getId());
                                            }
                                        } else {
                                            activityPlan.setActivityState(0);
                                            activityPlan.setRewardFlag(1);
                                            baseMapper.updateById(activityPlan);

                                            //完成活动
                                            Consumer<Long> afterFunction = successActivity.get(activityPlan.getActivityType());
                                            if (!Objects.isNull(afterFunction)) {
                                                afterFunction.accept(activityPlan.getId());
                                            }
                                        }
                                        return true;
                                    }, plan.getId(), 10l);
                }

            } catch (Exception e) {
                log.error("activityState time={}", DateTime.now().toString(MK.TIME_PATTERN), e);
            } finally {
                // 释放锁
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock(); // 删除同步标识
                }
            }

        });

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void activityIng() {

        // 当前处理任务调整为异步执行
        ThreadPool.getExecutor().submit(() -> {

            RLock lock = redissonClient.getLock(CacheNameEnum.LOCK_STANDARD_GIFT_CRON.getCode());
            try {
                if (lock.isLocked()) {
                    log.warn("activityIng {}, lockName={}", DateTime.now().toString(MK.TIME_PATTERN), lock.getName());
                    return;
                }

                // 增加达标活动计算同步标识，前一个请求未执行完时忽略后续执行请求
                lock.lock();

                for (ActivityTypeEnum activityTypeEnum : activityIng.keySet()) {
                    activityIng.get(activityTypeEnum).accept(null);
                }

            } catch (Exception e) {
                log.error("activityIng time={}", DateTime.now().toString(MK.TIME_PATTERN), e);
            } finally {
                // 释放锁
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock(); // 删除同步标识
                }
            }
        });

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveOrUpdateReward(SaveOrUpdateRewardDto saveOrUpdateRewardDto) {
        Long activityId = saveOrUpdateRewardDto.getActivityId();
        List<ActivityPlanRewardDto> updateRewardDtoList = saveOrUpdateRewardDto.getUpdateRewardDtoList();

		if(CollectionUtils.isEmpty(updateRewardDtoList)){
            updateRewardDtoList = new ArrayList<>();
        }

        // 活动信息
        ActivityPlan activityPlan = activityPlanDao.selectById(activityId);
        if (Objects.isNull(activityPlan)) {
            throw new BizException("无效的活动ID");
        }

        // 校验添加奖品与当前客户端是否匹配
        List<Long> collect = saveOrUpdateRewardDto.getUpdateRewardDtoList().stream()
                .map(ActivityPlanReward::getRewardId).distinct().collect(Collectors.toList());

        String clientType = activityPlan.getActivityClient().getCode();
        boolean invalidRewardNums = activityRewardService.listByIds(collect).stream()
                .anyMatch(x -> !Lists.newArrayList(x.getRewardClient().split(",")).contains(clientType));
        if (invalidRewardNums) {
            throw new BizException("添加奖品与活动客户端不匹配");
        }

        int ret = 0;
        if (ActivityTypeEnum.EVALUATION == activityPlan.getActivityType()) {

            // 当前活动曲目数
            ret = activityEvaluationService.count(Wrappers.<ActivityEvaluation>lambdaQuery()
                    .eq(ActivityEvaluation::getActivityId, activityId)
                    .eq(ActivityEvaluation::getResourceType, ActivityResourceEnum.MUSIC_SHEET));
        }

        ActivityPlanReward planReward;
        for (ActivityPlanRewardDto item : updateRewardDtoList) {
            // activityPlanRewardService.saveOrUpdateReward(item);

            // 设置默认值
            if (StringUtils.isEmpty(item.getGroup())) {
                item.setGroup("1");
            }

            item.setRewardStock(item.getRewardNum());
            // 评测活动
            if (ActivityTypeEnum.EVALUATION == activityPlan.getActivityType()) {
                item.rewardStock(ret).setRewardNum(ret);
            }
            planReward = activityPlanRewardService.detailByActivityIdAndRewardId(item.getActivityId(), item.getRewardId(), item.getGroup());

            if (Objects.isNull(planReward)) {

                // 新增
                activityPlanRewardService.save(item);
            } else {

                // 更新
                item.setId(planReward.getId());

                activityPlanRewardService.updateById(item);
            }
        }

        //还有删除的
        List<Long> rewardIds = updateRewardDtoList.stream().map(ActivityPlanRewardDto::getRewardId).collect(Collectors.toList());
        List<ActivityPlanReward> delList = activityPlanRewardService.getDelRewardList(activityId, rewardIds);
        for (ActivityPlanReward reward : delList) {
            //修改库存
            activityPlanRewardService.recoveryReward(reward);
            //删除活动奖品
            activityPlanRewardService.removeById(reward.getId());
        }
        return true;
    }

    @Override
    public ActivityPlanVo activityShare(ActivityShareEnum type, Long userId) {
        if (userId == null || type == null) {
            return null;
        }
        ActivityPlanVo detail = baseMapper.selectActivityShare(type.getCode(), userId);
        if (detail ==null) {
            return null;
        }
        //查询活动奖品
        List<ActivityPlanRewardDto> activityRewardList = activityPlanRewardService.queryActivityPlanReward(detail.getId());
        detail.setActivityRewardList(activityRewardList);
        return detail;
    }

    @Override
    public YesOrNoEnum state(Long activityId) {
        List<ActivityPlan> list = this.lambdaQuery()
                                      .eq(ActivityPlan::getId, activityId)
                                      .eq(ActivityPlan::getActivityState, 1)
                                      .list();
        return CollectionUtils.isEmpty(list)?YesOrNoEnum.NO:YesOrNoEnum.YES;

    }

    /**
     * 参与活动消息
     */
    private void sendMessage(String activityName, Long userId) {
        try {
            //  发送消息
            SysUser user = sysUserFeignService.queryUserById(userId);

            Map<Long, String> receivers = new HashMap<>();
            receivers.put(userId, user.getPhone());

            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.ACTIVITY_JOIN_MESSAGE, receivers, null,
                    0, null, ClientEnum.STUDENT.getCode(), activityName);

        } catch (Exception e) {
            log.error("活动参与发送消息失败--> {}", e.fillInStackTrace());
        }
    }

    private void checkActivityPay(Long planId) {
        if (planId == null) {
            throw new BizException("活动id不能为空");
        }
        ActivityPlan activityPlan = getById(planId);

        if (activityPlan.getActivityState() == 0) {
            throw new BizException("活动已结束");
        }
        if (new Date().compareTo(activityPlan.getActivityStart()) < 0) {
            throw new BizException("活动未开始");
        }
        if (new Date().compareTo(activityPlan.getActivityEnd()) > 0) {
            throw new BizException("活动已结束");
        }
    }

    private SysUser getSysUser(Long userId) {
        return Optional.ofNullable(userId)
                .map(sysUserFeignService::queryUserById)
                .orElseThrow(() -> new BizException("用户不存在"));
    }
}