package com.zhongzheng.modules.activity.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.zhongzheng.common.utils.DateUtils;
import com.zhongzheng.modules.activity.bo.ActivityTaskUserAddBo;
import com.zhongzheng.modules.activity.domain.ActivityGrade;
import com.zhongzheng.modules.activity.service.IActivityGradeService;
import com.zhongzheng.modules.activity.service.IActivityTaskService;
import com.zhongzheng.modules.activity.service.IActivityTaskTimeService;
import com.zhongzheng.modules.activity.vo.ActivityGradeVo;
import com.zhongzheng.modules.activity.vo.ActivityTaskTimeVo;
import com.zhongzheng.modules.activity.vo.ActivityTaskVo;
import com.zhongzheng.modules.user.domain.User;
import com.zhongzheng.modules.user.service.IUserService;
import com.zhongzheng.modules.user.vo.UserVo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.zhongzheng.modules.activity.bo.ActivityTaskUserQueryBo;
import com.zhongzheng.modules.activity.bo.ActivityTaskUserEditBo;
import com.zhongzheng.modules.activity.domain.ActivityTaskUser;
import com.zhongzheng.modules.activity.mapper.ActivityTaskUserMapper;
import com.zhongzheng.modules.activity.vo.ActivityTaskUserVo;
import com.zhongzheng.modules.activity.service.IActivityTaskUserService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户领取记录Service业务层处理
 *
 * @author ruoyi
 * @date 2021-06-16
 */
@Service
public class ActivityTaskUserServiceImpl extends ServiceImpl<ActivityTaskUserMapper, ActivityTaskUser> implements IActivityTaskUserService {

    @Autowired
    private IUserService userService;

    @Autowired
    private IActivityGradeService activityGradeService;

    @Autowired
    private IActivityTaskService activityTaskService;

    @Autowired
    private IActivityTaskTimeService activityTaskTimeService;


    @Override
    public ActivityTaskUserVo queryById(Long userId){
        ActivityTaskUser db = this.baseMapper.selectById(userId);
        return BeanUtil.toBean(db, ActivityTaskUserVo.class);
    }

    @Override
    public List<ActivityTaskUserVo> queryList(ActivityTaskUserQueryBo bo) {
        LambdaQueryWrapper<ActivityTaskUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(StrUtil.isNotBlank(bo.getScore()), ActivityTaskUser::getScore, bo.getScore());
        lqw.eq(bo.getTaskType() != null, ActivityTaskUser::getTaskType, bo.getTaskType());
        return entity2Vo(this.list(lqw));
    }

    /**
    * 实体类转化成视图对象
    *
    * @param collection 实体类集合
    * @return
    */
    private List<ActivityTaskUserVo> entity2Vo(Collection<ActivityTaskUser> collection) {
        List<ActivityTaskUserVo> voList = collection.stream()
                .map(any -> BeanUtil.toBean(any, ActivityTaskUserVo.class))
                .collect(Collectors.toList());
        if (collection instanceof Page) {
            Page<ActivityTaskUser> page = (Page<ActivityTaskUser>)collection;
            Page<ActivityTaskUserVo> pageVo = new Page<>();
            BeanUtil.copyProperties(page,pageVo);
            pageVo.addAll(voList);
            voList = pageVo;
        }
        return voList;
    }

    @Override
    public Boolean insertByAddBo(ActivityTaskUserAddBo bo) {
        ActivityTaskUser add = BeanUtil.toBean(bo, ActivityTaskUser.class);
        validEntityBeforeSave(add);
        add.setCreateTime(DateUtils.getNowTime());
        add.setUpdateTime(DateUtils.getNowTime());
        return this.save(add);
    }

    @Override
    public Boolean updateByEditBo(ActivityTaskUserEditBo bo) {
        ActivityTaskUser update = BeanUtil.toBean(bo, ActivityTaskUser.class);
        validEntityBeforeSave(update);
        update.setUpdateTime(DateUtils.getNowTime());
        return this.updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(ActivityTaskUser entity){
        //TODO 做一些数据校验,如唯一约束
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return this.removeByIds(ids);
    }

    /**
     * 签到领取积分
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean userTask(ActivityTaskUserAddBo bo) {
        //判断是否是签到
        if (bo.getTaskType() != 0){
            throw new IllegalArgumentException("该请求是签到请求");
        }

        //判断是否领过过
        validReceiver(bo);

        //增加用户积分，并判断是否达到对应等级，更新等级
        UserVo userVo = userService.queryById(bo.getUserId());
        ActivityTaskVo activityTaskVo = activityTaskService.queryByTaskId(Convert.toLong(bo.getTaskType()));

        //签到逻辑连续签到获得累加积分，断了为初始积分
        LambdaQueryWrapper<ActivityTaskUser> lqw =Wrappers.lambdaQuery();;
        lqw.eq(bo.getUserId() != null,ActivityTaskUser::getUserId,bo.getUserId());
        lqw.eq(bo.getTaskType() != null, ActivityTaskUser::getTaskType, bo.getTaskType());
        lqw.between( ActivityTaskUser::getCreateTime, getDateOne(),DateUtils.getNowTime());
        List<ActivityTaskUser> list = this.list(lqw);
        List<SignIn> signIn = new ArrayList<>();
        list.forEach(s -> {
            try {
                signIn.add(new SignIn(s.getCreateTime().toString()));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        });

        //连续签到的天数，不包括今天，即第一天1积分第二天2积分
        int continuousSignInDay = getContinuousSignInDay(signIn);
        //天数*每次累加分数得出今天分数
        if (continuousSignInDay == 0){
            continuousSignInDay =1;
        }
        int fen = activityTaskVo.getAccIntegral()*continuousSignInDay;
        if (userVo.getIntegral() == null){
            userVo.setIntegral(0L);
        }
        Long score = userVo.getIntegral()+fen;

        //分数达到的等级赋予学生等级
        //增加用户领取记录
        ActivityTaskUser add = BeanUtil.toBean(bo, ActivityTaskUser.class);
        add.setCreateTime(DateUtils.getNowTime());
        add.setUpdateTime(DateUtils.getNowTime());
        ActivityGradeVo list1 = activityGradeService.queryByInteger(score);
        add.setScore(Convert.toStr(fen));

        //增加用户积分和等级
        userVo.setUserLevel(list1.getGrade());
        increaseUser(userVo,score);
        add.setUserId(bo.getUserId());
        add.setTaskId(activityTaskVo.getId());

        return this.save(add);
    }



    /**
     * 完善信息领取积分
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean information(ActivityTaskUserAddBo bo) throws IllegalAccessException {
        //判断是否是完善信息
        if (bo.getTaskType() != 1){
            throw new IllegalArgumentException("该请求是完善信息");
        }
        validReceiver(bo);

        ActivityTaskVo activityTaskVo = activityTaskService.queryById(bo.getTaskId());

       //得出已领取的分数是多少
        LambdaQueryWrapper<ActivityTaskUser> lqw =Wrappers.lambdaQuery();;
        lqw.eq(bo.getUserId() != null,ActivityTaskUser::getUserId,bo.getUserId());
        lqw.eq(bo.getTaskType() != null, ActivityTaskUser::getTaskType, bo.getTaskType());
        List<ActivityTaskUser> list = this.list(lqw);
        BigDecimal bigDecimal = new BigDecimal("0");
        if (!CollectionUtils.isEmpty(list)) {
            for (ActivityTaskUser activityTaskUser : list) {
                bigDecimal = bigDecimal.add(new BigDecimal(activityTaskUser.getScore()));
            }
        }

        //userVO用户  有参值/总数 得出比例 乘以分数 四舍五入
        UserVo userVo = userService.queryById(bo.getUserId());
        Field[] field = userVo.getClass().getDeclaredFields();
        Integer integer = countUser(userVo);
        String num = String.valueOf(integer/ field.length);
        BigDecimal result5 = new BigDecimal(activityTaskVo.getEndIntegral().toString()).divide(new BigDecimal(num),BigDecimal.ROUND_HALF_UP);

        //增加用户领取记录
        ActivityTaskUser add = BeanUtil.toBean(bo, ActivityTaskUser.class);
        add.setScore(bigDecimal.subtract(result5).toString());
        add.setCreateTime(DateUtils.getNowTime());
        add.setUpdateTime(DateUtils.getNowTime());

        //增加用户积分更新等级
        Long Integer = userVo.getIntegral()+ Convert.toLong(bigDecimal.subtract(result5));
        ActivityGradeVo list1 = activityGradeService.queryByInteger(Integer);
        userVo.setUserLevel(list1.getGrade());
        increaseUser(userVo,Integer);

        return this.save(add);
    }

    /**
     * 邀请好友
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean invitation(ActivityTaskUserAddBo bo) {
        //判断是否是邀请好友
        if (bo.getTaskType() != 2){
            throw new IllegalArgumentException("该请求是邀请好友");
        }
        validReceiver(bo);

        ActivityTaskVo activityTaskVo = activityTaskService.queryByTaskId(Convert.toLong(bo.getTaskType()));

        //增加用户积分
        UserVo userVo = userService.queryById(bo.getUserId());
        ActivityGradeVo list1 = activityGradeService.queryByInteger(userVo.getIntegral()+activityTaskVo.getStartIntegral());
        userVo.setUserLevel(list1.getGrade());
        increaseUser(userVo,userVo.getIntegral()+activityTaskVo.getStartIntegral());

        //增加领取记录
        ActivityTaskUser add = BeanUtil.toBean(bo, ActivityTaskUser.class);
        add.setScore(Convert.toStr(activityTaskVo.getStartIntegral()));
        add.setCreateTime(DateUtils.getNowTime());
        add.setUpdateTime(DateUtils.getNowTime());
        add.setUserId(bo.getUserId());
        add.setTaskId(activityTaskVo.getId());
        return this.save(add);
    }


    /**
     * 每日分享
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean share(ActivityTaskUserAddBo bo) {
        //判断是否是每日分享
        if (bo.getTaskType() != 3){
            throw new IllegalArgumentException("该请求是完善信息");
        }
        validReceiver(bo);

        ActivityTaskVo activityTaskVo = activityTaskService.queryByTaskId(Convert.toLong(bo.getTaskType()));

        //增加用户积分
        UserVo userVo = userService.queryById(bo.getUserId());
        ActivityGradeVo list1 = activityGradeService.queryByInteger(userVo.getIntegral()+activityTaskVo.getStartIntegral());
        userVo.setUserLevel(list1.getGrade());
        increaseUser(userVo,userVo.getIntegral()+activityTaskVo.getStartIntegral());

        //增加领取记录
        ActivityTaskUser add = BeanUtil.toBean(bo, ActivityTaskUser.class);
        add.setScore(Convert.toStr(activityTaskVo.getStartIntegral()));
        add.setCreateTime(DateUtils.getNowTime());
        add.setUpdateTime(DateUtils.getNowTime());
        add.setUserId(bo.getUserId());
        add.setTaskId(activityTaskVo.getId());
        return this.save(add);
    }


    /**
     * 学习时长
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer learnTime(ActivityTaskUserAddBo bo) {
        //判断是否是每日分享
        if (bo.getTaskType() != 4){
            throw new IllegalArgumentException("该请求是学习时长");
        }
        if (validReceiver(bo) == false){
            return 0;
        }

        ActivityTaskVo activityTaskVo = activityTaskService.queryByTaskId(Convert.toLong(bo.getTaskType()));

        //增加用户积分
        if ((activityTaskVo.getLongTime()*60) > Convert.toInt(bo.getScore())) {
            return 0;
        }
        Integer integer = (int)Math.ceil(Convert.toInt(bo.getScore())/(activityTaskVo.getLongTime()*60));

            UserVo userVo = userService.queryById(bo.getUserId());
            Long socor = 0L;
            if (userVo.getIntegral() != null) {
                socor = userVo.getIntegral() + (activityTaskVo.getStartIntegral() * integer);
            }else {
                socor =  Convert.toLong(activityTaskVo.getStartIntegral() * integer);

            }
        ActivityGradeVo list1 = activityGradeService.queryByInteger(socor);
            userVo.setUserLevel(list1.getGrade());
            increaseUser(userVo, socor);

        //增加领取记录
        ActivityTaskUser add = BeanUtil.toBean(bo, ActivityTaskUser.class);
        add.setScore(Convert.toStr(activityTaskVo.getStartIntegral()));
        add.setCreateTime(DateUtils.getNowTime());
        add.setUpdateTime(DateUtils.getNowTime());
        add.setTaskType(bo.getTaskType());
        add.setUserId(bo.getUserId());
        add.setTaskId(activityTaskVo.getId());
        this.save(add);
        return (activityTaskVo.getStartIntegral()*integer);
    }


    /**
     * 模拟考试
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean practiceTest(ActivityTaskUserAddBo bo) {
        //判断是否是模拟考试
        if (bo.getTaskType() != 5){
            throw new IllegalArgumentException("该请求是模拟考试");
        }
        validReceiver(bo);

        ActivityTaskVo activityTaskVo = activityTaskService.queryById(bo.getTaskId());
        bo.setTaskId(activityTaskVo.getId());
        ActivityTaskTimeVo activityTaskTimeVo = activityTaskTimeService.queryPractice(bo);

        //增加用户积分
        UserVo userVo = userService.queryById(bo.getUserId());
        ActivityGradeVo list1 = activityGradeService.queryByInteger(userVo.getIntegral()+activityTaskVo.getStartIntegral());
        userVo.setUserLevel(list1.getGrade());
        increaseUser(userVo,userVo.getIntegral()+Convert.toLong(activityTaskTimeVo.getIntegral()));

        //增加领取记录
        ActivityTaskUser add = BeanUtil.toBean(bo, ActivityTaskUser.class);
        add.setScore(Convert.toStr(activityTaskVo.getStartIntegral()));
        return this.save(add);
    }

    private Boolean increaseUser(UserVo userVo,Long score){
        User user = BeanUtil.toBean(userVo, User.class);
        user.setIntegral(score);
        user.setUpdateTime(DateUtils.getNowTime());
        return userService.updateById(user);
    }

    /**
     *
     * @author change
     * @date 2021/6/23 14:38
     * @param userVo
     * @return Integer
     */
    public Integer  countUser(UserVo userVo) throws IllegalAccessException {
        // Java的反射
        Field[] field = userVo.getClass().getDeclaredFields();
        int count = 0;
        for(int i=0; i<field.length; i++){
            Field f = field[i];
            f.setAccessible(true);
            if (f.get(userVo) != null){
                count++;
            }
        }
        return count;
    }



    //获得过去七天的日期
    private Long getDateOne(){
        Calendar c = Calendar.getInstance();
        //过去七天
        c.setTime(new Date());
        c.add(Calendar.DATE, - 7);
        Date d = c.getTime();

        return d.getTime();
    }


    private Boolean validReceiver(ActivityTaskUserAddBo bo) {
        ActivityTaskVo activityTaskVo = activityTaskService.queryByTaskId(bo.getTaskId());
        switch (bo.getTaskType()){
            //每日签到逻辑，当日有领取即无法签到
            case 0:
                LambdaQueryWrapper<ActivityTaskUser> lqw = Wrappers.lambdaQuery();
                lqw.eq(bo.getTaskType() !=null,ActivityTaskUser::getTaskType,bo.getTaskType());
                lqw.eq(bo.getUserId() !=null,ActivityTaskUser::getUserId,bo.getUserId());
                lqw.between(ActivityTaskUser::getCreateTime,getTimesmorning(),getTimesnight());
                List<ActivityTaskUser> list = this.list(lqw);
                if (!CollectionUtils.isEmpty(list) && list.size() > 0){
                    throw new IllegalArgumentException("已签到请勿重复签到");
                }
                break;
                //完善信息  按照百分比求得乘以分数得到奖励分数
            case 1:
                LambdaQueryWrapper<ActivityTaskUser> useWan = Wrappers.lambdaQuery();
                useWan.eq(bo.getTaskType() !=null,ActivityTaskUser::getTaskType,bo.getTaskType());
                useWan.eq(bo.getUserId() !=null,ActivityTaskUser::getUserId,bo.getUserId());
                List<ActivityTaskUser> listWan = this.list(useWan);
                BigDecimal bigDecimal = new BigDecimal("0");
                for (ActivityTaskUser activityTaskUser : listWan) {
                    bigDecimal = bigDecimal.add(new BigDecimal(activityTaskUser.getScore()));
                }
                if (bigDecimal.compareTo(new BigDecimal(activityTaskVo.getAccIntegral())) != 0){
                    throw new IllegalArgumentException("已完善信息领取完成，无法再次领取");
                }
                break;
            case 2:
                break;
            case 3:
                //每日分享，大于三次达到上线
                LambdaQueryWrapper<ActivityTaskUser> useMei = Wrappers.lambdaQuery();
                useMei.eq(bo.getTaskType() !=null,ActivityTaskUser::getTaskType,bo.getTaskType());
                useMei.eq(bo.getUserId() !=null,ActivityTaskUser::getUserId,bo.getUserId());
                useMei.between(ActivityTaskUser::getCreateTime,getTimesmorning(),getTimesnight());
                List<ActivityTaskUser> listMei = this.list(useMei);
                if (!CollectionUtils.isEmpty(listMei) && listMei.size() == 3){
                    throw new IllegalArgumentException("当日分享已达上线");
                }
                break;
            case 4:
                //连续学习，大于三次达到上线
                LambdaQueryWrapper<ActivityTaskUser> study = Wrappers.lambdaQuery();
                study.eq(bo.getTaskType() !=null,ActivityTaskUser::getTaskType,bo.getTaskType());
                study.eq(bo.getUserId() !=null,ActivityTaskUser::getUserId,bo.getUserId());
                study.between(ActivityTaskUser::getCreateTime,getTimesmorning(),getTimesnight());
                List<ActivityTaskUser> listStudy = this.list(study);
                Integer score = 0;
                for (ActivityTaskUser activityTaskUser : listStudy) {
                     score = score+Convert.toInt(activityTaskUser.getScore());
                }
                if (!CollectionUtils.isEmpty(listStudy) && activityTaskVo.getEndIntegral().equals(score)){
                    return false;
                }
                break;
            case 5:
                LambdaQueryWrapper<ActivityTaskUser> practice = Wrappers.lambdaQuery();
                practice.eq(bo.getTaskType() !=null,ActivityTaskUser::getTaskType,bo.getTaskType());
                practice.eq(bo.getUserId() !=null,ActivityTaskUser::getUserId,bo.getUserId());
                practice.between(ActivityTaskUser::getCreateTime,getTimesmorning(),getTimesnight());
                List<ActivityTaskUser> listPractice = this.list(practice);
                if (!CollectionUtils.isEmpty(listPractice) && listPractice.size() > 0){
                    throw new IllegalArgumentException("当日领取连续模拟考试积分已达上线");
                }
                break;
        }
        return true;
    }


    //获得今天时间的0点
    public static int getTimesmorning(){
        Calendar cal = Calendar.getInstance();

        cal.set(Calendar.HOUR_OF_DAY, 0);

        cal.set(Calendar.SECOND, 0);

        cal.set(Calendar.MINUTE, 0);

        cal.set(Calendar.MILLISECOND, 0);

        return (int) (cal.getTimeInMillis()/1000);

    }

    //获得当天24点时间
    public static int getTimesnight(){
        Calendar cal = Calendar.getInstance();

        cal.set(Calendar.HOUR_OF_DAY, 24);

        cal.set(Calendar.SECOND, 0);

        cal.set(Calendar.MINUTE, 0);

        cal.set(Calendar.MILLISECOND, 0);

        return (int) (cal.getTimeInMillis()/1000);

    }

    /**
     * 连续签到天数
     *
     * @return int
     * @Author change
     * @Date 2021-06-23
     * @Param
     **/
    private static int getContinuousSignInDay(List<SignIn> signInList) {
        //continuousDay 连续签到数
        int continuousDay = 1;
        boolean todaySignIn = true;
        Date today = new Date();
        for (int i = 0; i < signInList.size(); i++) {
            SignIn signIn = signInList.get(i);
            int intervalDay = distanceDay(today, signIn.getSignInDay());
            //当天签到
            if (intervalDay == 0 && i == 0) {
                todaySignIn = true;
            }
            else if (intervalDay == continuousDay) {
                continuousDay++;
            }else {
                //不连续，终止判断
                break;
            }
        }
        if (!todaySignIn) {
            continuousDay--;
        }
        return continuousDay;
    }

    /**
     * 两个日期对比间隔天数
     *
     * @param smallDay
     * @return boolean
     * @Author change
     * @Date 2021-06-23
     * @Param largeDay
     **/
    private static int distanceDay(Date largeDay, Date smallDay) {
        int day = (int) ((largeDay.getTime() - smallDay.getTime()) / (1000 * 60 * 60 * 24));
        return day;
    }

    @Data
    static
    class SignIn{
        private Date signInDay;

        public SignIn(){

        }

        public SignIn(String day) throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String sd = sdf.format(new Date(Long.parseLong(String.valueOf(day))));
            signInDay = sdf.parse(day);
        }
    }


}
