package com.ylx.point.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylx.common.core.domain.model.WxLoginUser;
import com.ylx.common.exception.ServiceException;
import com.ylx.common.utils.DateUtils;
import com.ylx.common.utils.SecurityUtils;
import com.ylx.order.service.TOrderService;
import com.ylx.massage.service.TRechargeService;
import com.ylx.point.domain.PointActivity;
import com.ylx.point.domain.PointActivityTask;
import com.ylx.point.domain.PointUserActivityTaskCompletion;
import com.ylx.point.domain.vo.PointActivityOverviewVO;
import com.ylx.point.enums.*;
import com.ylx.point.enums.TaskNameEnum;
import com.ylx.point.mapper.PointUserActivityTaskCompletionMapper;
import com.ylx.point.service.IPointAccountService;
import com.ylx.point.service.IPointActivityService;
import com.ylx.point.service.IPointActivityTaskService;
import com.ylx.point.service.IPointUserActivityTaskCompletionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户活动任务完成Service业务层处理
 * JDK8 兼容版
 *
 * @author wzj
 * @date 2026-03-25
 */
@Slf4j
@Service
public class PointUserActivityTaskCompletionServiceImpl extends ServiceImpl<PointUserActivityTaskCompletionMapper, PointUserActivityTaskCompletion> implements IPointUserActivityTaskCompletionService {

    @Resource
    private PointUserActivityTaskCompletionMapper pointUserActivityTaskCompletionMapper;
    @Resource
    private IPointActivityTaskService pointActivityTaskService;
    @Resource
    private IPointActivityService pointActivityService;
    @Resource
    private TOrderService orderService;
    @Resource
    private TRechargeService rechargeService;
    @Resource
    private IPointAccountService pointAccountService;

    /**
     * 活动类型优先级：新手活动 > 每日活动 > 每月活动
     */
    private static final List<Integer> ACTIVITY_TYPE_PRIORITY = Arrays.asList(PointActivityTypeEnum.NEW_USER_ACTIVITY.getCode(), PointActivityTypeEnum.DAILY_ACTIVITY.getCode(), PointActivityTypeEnum.MONTHLY_ACTIVITY.getCode());

    @Override
    public PointActivityOverviewVO getPointActivityOverviewByActivityId(Long activityId) {
        return pointUserActivityTaskCompletionMapper.getPointActivityOverviewByActivityId(activityId);
    }

    @Override
    public Integer selectCompletedTaskCount(String openId) {
        return pointUserActivityTaskCompletionMapper.selectCompletedTaskCount(openId);
    }

    @Override
    public List<PointUserActivityTaskCompletion> selectCompletionsByOpenIdAndTaskIds(String openId, List<Long> taskIds) {
        if (CollectionUtil.isEmpty(taskIds)) {
            return Collections.emptyList();
        }
        return pointUserActivityTaskCompletionMapper.selectCompletionsByOpenIdAndTaskIds(openId, taskIds);
    }

    /**
     * 判断用户今日是否已完成该任务（用于每日一次任务、每日签到）
     */
    @Override
    public boolean isTodayCompleted(String openId, Long activityId, Long taskId, Integer taskType) {
        return pointUserActivityTaskCompletionMapper.exists(Wrappers.lambdaQuery(PointUserActivityTaskCompletion.class).eq(PointUserActivityTaskCompletion::getOpenId, openId).eq(PointUserActivityTaskCompletion::getActivityId, activityId).eq(PointUserActivityTaskCompletion::getTaskId, taskId).eq(PointUserActivityTaskCompletion::getTaskType, taskType).eq(PointUserActivityTaskCompletion::getCompletedDate, LocalDate.now()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeTask(String openId, Long activityId, Long taskId, Integer taskType) {
        // 1. 查询是否存在记录
        PointUserActivityTaskCompletion completion = this.getOne(Wrappers.lambdaQuery(PointUserActivityTaskCompletion.class)
                .eq(PointUserActivityTaskCompletion::getOpenId, openId)
                .eq(PointUserActivityTaskCompletion::getActivityId, activityId)
                .eq(PointUserActivityTaskCompletion::getTaskId, taskId)
                .eq(PointUserActivityTaskCompletion::getTaskType, taskType)
        );

        if (ObjectUtil.isNull(completion)) {
            // 首次完成：插入
            PointUserActivityTaskCompletion insert = new PointUserActivityTaskCompletion();
            insert.setOpenId(openId);
            insert.setActivityId(activityId);
            insert.setTaskId(taskId);
            insert.setTaskType(taskType);
            insert.setCompletedCount(1);
            insert.setLastCompletedTime(DateUtils.getNowDate());
            this.save(insert);
        } else {
            // 非首次：原子更新次数+1
            this.update(Wrappers.lambdaUpdate(PointUserActivityTaskCompletion.class)
                    .eq(PointUserActivityTaskCompletion::getId, completion.getId())
                    .setSql("completed_count = completed_count + 1")
                    .set(PointUserActivityTaskCompletion::getLastCompletedTime, DateUtils.getNowDate())
            );
        }
    }

    @Override
    public int getUserTaskTotalCount(String openId, Long activityId, Long taskId, Integer taskType) {
        PointUserActivityTaskCompletion completion = this.getOne(Wrappers.lambdaQuery(PointUserActivityTaskCompletion.class)
                .eq(PointUserActivityTaskCompletion::getOpenId, openId)
                .eq(PointUserActivityTaskCompletion::getActivityId, activityId)
                .eq(PointUserActivityTaskCompletion::getTaskId, taskId)
                .eq(PointUserActivityTaskCompletion::getTaskType, taskType)
        );
        return completion == null ? 0 : completion.getCompletedCount();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executeTask(Long taskId) {
        // 1. 获取登录用户
        WxLoginUser loginUser = getCurrentWxLoginUser();
        String openId = loginUser.getCOpenid();

        // 2. 校验任务
        PointActivityTask task = pointActivityTaskService.getById(taskId);
        if (ObjectUtil.isNull(task)) {
            throw new ServiceException("任务不存在");
        }

        // 3. 校验活动
        PointActivity activity = pointActivityService.getById(task.getActivityId());
        if (ObjectUtil.isNull(activity) || !PointActivityStatusEnum.IN_PROGRESS.getCode().equals(activity.getStatus())) {
            throw new ServiceException("活动不存在或已结束");
        }

        Long activityId = activity.getId();
        Integer activityType = activity.getActivityType();
        PointActivityTaskTypeEnum taskTypeEnum = PointActivityTaskTypeEnum.getByInfo(task.getTaskName());
        int targetCount = Integer.parseInt(task.getTriggerValue());

        // 4. 任务校验逻辑
        List<Integer> validTypes = Arrays.asList(
                PointActivityTypeEnum.DAILY_ACTIVITY.getCode(),
                PointActivityTypeEnum.NEW_USER_ACTIVITY.getCode(),
                PointActivityTypeEnum.MONTHLY_ACTIVITY.getCode()
        );
        if (!validTypes.contains(activityType)) {
            throw new ServiceException("不支持的活动类型");
        }

        // 每日/新手/月度任务：校验业务数据
        String taskName = getTaskNameByType(taskTypeEnum);
        // 分享服务号、浏览动态和浏览商户
        boolean isVerified = checkBusinessData(taskTypeEnum);

        // 5. 校验通过 → 发放奖励
        if (isVerified) {
            Date queryTime = getQueryStartTime(activity.getIsPermanent(), activity.getActivityType());
            // 防重复发奖：已达标则直接返回
            PointUserActivityTaskCompletion record = this.getTaskRecordInPeriod(openId, activityId, taskId, taskTypeEnum.getCode(), queryTime);
            if (ObjectUtil.isNotNull(record) && record.getCompletedCount() >= targetCount) {
                throw new ServiceException("任务奖励已领取");
            }

            // 更新任务进度
            this.completeTask(openId, activityId, taskId, taskTypeEnum.getCode());
            // 发放积分
            pointAccountService.addPoints(openId, task.getRewardPoints().intValue(),
                    activity.getName(), null, activityId, taskId, taskTypeEnum.getCode(), taskName);
        } else {
            throw new ServiceException("任务未完成，无法领取奖励");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeOrderTaskByPriority(String openId) {
        completeTaskByPriority(openId, TaskNameEnum.COMPLETE_ORDER, PointActivityTaskTypeEnum.COMPLETE_ORDER);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeRechargeTaskByPriority(String openId) {
        completeTaskByPriority(openId, TaskNameEnum.RECHARGE_TASK, PointActivityTaskTypeEnum.RECHARGE_TASK);
    }

    /**
     * 根据任务类型获取任务名称 JDK8 兼容
     */
    private String getTaskNameByType(PointActivityTaskTypeEnum taskType) {
        if (taskType == PointActivityTaskTypeEnum.COMPLETE_ORDER) {
            return TaskNameEnum.COMPLETE_ORDER.getInfo();
        } else if (taskType == PointActivityTaskTypeEnum.RECHARGE_TASK) {
            return TaskNameEnum.RECHARGE_TASK.getInfo();
        } else if (taskType == PointActivityTaskTypeEnum.SHARE_SERVICE) {
            return TaskNameEnum.SHARE_ACCOUNT.getInfo();
        } else if (taskType == PointActivityTaskTypeEnum.BROWLE_NEWS) {
            return TaskNameEnum.BROWSE_DYNAMIC.getInfo();
        } else if (taskType == PointActivityTaskTypeEnum.BROWLE_MERCHANT) {
            return TaskNameEnum.BROWSE_MERCHANT.getInfo();
        } else {
            throw new ServiceException("不支持的任务类型: " + taskType);
        }
    }

    /**
     * 校验业务数据(只针对：分享服务号、浏览动态和浏览商户)
     */
    private boolean checkBusinessData(PointActivityTaskTypeEnum taskType) {
        boolean bool = false;
        if (taskType == PointActivityTaskTypeEnum.SHARE_SERVICE
                || taskType == PointActivityTaskTypeEnum.BROWLE_NEWS
                || taskType == PointActivityTaskTypeEnum.BROWLE_MERCHANT) {
            bool = true;
        }
        return bool;
    }

    /**
     * 获取查询开始时间,
     * 永久任务、新手活动:null
     * 每日活动: 当天0点0分0秒
     * 每月活动：当前月的第一天的0点0分0秒
     */
    private Date getQueryStartTime(String isPermanent, Integer activityType) {
        Date StartTime = null;
        // 永久任务：查询全部历史
        if (StrUtil.equals(isPermanent, "1")) {
            return StartTime;
        }
        PointActivityTypeEnum typeEnum = PointActivityTypeEnum.valueOf(activityType);
        if (typeEnum == PointActivityTypeEnum.DAILY_ACTIVITY) {
            StartTime = DateUtil.beginOfDay(new Date());
        } else if (typeEnum == PointActivityTypeEnum.MONTHLY_ACTIVITY) {
            StartTime = DateUtil.beginOfMonth(new Date());
        } else if (typeEnum == PointActivityTypeEnum.NEW_USER_ACTIVITY) {
            // 获取正在进行中的新手活动
            LambdaQueryWrapper<PointActivity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(PointActivity::getActivityType, PointActivityTypeEnum.NEW_USER_ACTIVITY.getCode())
                    .eq(PointActivity::getStatus, 1)
                    .orderByDesc(PointActivity::getStartTime)
                    .last("limit 1");
            PointActivity activity = this.pointActivityService.getOne(queryWrapper);
            if (ObjectUtil.isNotNull(activity)) {
                StartTime = activity.getStartTime();
            }
        }
        return StartTime;
    }

    /**
     * 获取当前微信登录用户
     */
    private WxLoginUser getCurrentWxLoginUser() {
        WxLoginUser loginUser = SecurityUtils.getWxLoginUser();
        if (ObjectUtil.isNull(loginUser)) {
            throw new ServiceException("用户未登录或登录已过期");
        }
        return loginUser;
    }

    /**
     * 查询当前周期内的任务记录
     * 这里需要你修改 Mapper/DAO 层，支持按时间范围查询
     */
    private PointUserActivityTaskCompletion getTaskRecordInPeriod(String openId, Long activityId, Long taskId, Integer taskTypeCode, Date startTime) {
        // 构建查询条件
        LambdaQueryWrapper<PointUserActivityTaskCompletion> wrapper = Wrappers.lambdaQuery(PointUserActivityTaskCompletion.class).eq(PointUserActivityTaskCompletion::getOpenId, openId).eq(PointUserActivityTaskCompletion::getActivityId, activityId).eq(PointUserActivityTaskCompletion::getTaskId, taskId).eq(PointUserActivityTaskCompletion::getTaskType, taskTypeCode);

        // 核心：如果 startTime 不为空，则限制在该时间之后（即本周期内）
        if (startTime != null) {
            wrapper.ge(PointUserActivityTaskCompletion::getCreateTime, startTime);
        }

        return this.getOne(wrapper);
    }

    /**
     * 通用优先级任务完成方法
     * 按活动类型优先级（新手 > 每日 > 每月）遍历匹配任务，完成首个合格任务后立即返回
     */
    private void completeTaskByPriority(String openId, TaskNameEnum activityNameEnum, PointActivityTaskTypeEnum taskTypeEnum) {

        // 1. 检查用户是否已经完成过任何新手活动
        boolean hasCompletedNewUser = checkIfUserCompletedAnyNewUserTask(openId);

        // 2. 批量查询所有有效任务
        List<PointActivityTask> allTasks = pointActivityTaskService.list(Wrappers.lambdaQuery(PointActivityTask.class)
                .eq(PointActivityTask::getTaskName, activityNameEnum.getInfo())
                .eq(PointActivityTask::getStatus, 0)
                .eq(PointActivityTask::getIsDeleted, 0));
        if (CollectionUtil.isEmpty(allTasks)) {
            return;
        }

        // 3. 批量查询关联活动，避免N+1查询
        Set<Long> activityIds = allTasks.stream().map(PointActivityTask::getActivityId).collect(Collectors.toSet());
        Map<Long, PointActivity> activityMap = pointActivityService.listByIds(activityIds).stream()
                .collect(Collectors.toMap(PointActivity::getId, a -> a));

        // 4. 根据新手任务状态决定遍历的优先级
        List<Integer> targetPriorities;
        if (hasCompletedNewUser) {
            // 如果已经完成过新手活动，则只处理每日和每月
            targetPriorities = Arrays.asList(
                    PointActivityTypeEnum.DAILY_ACTIVITY.getCode(),
                    PointActivityTypeEnum.MONTHLY_ACTIVITY.getCode()
            );
        } else {
            // 否则，按照默认优先级（新手>每日>每月）处理
            targetPriorities = ACTIVITY_TYPE_PRIORITY;
        }
        // ----------------------------------------------------

        // 5. 按优先级遍历活动类型
        for (Integer typeCode : targetPriorities) {
            List<PointActivityTask> filteredTasks = filterValidTasks(allTasks, activityMap, typeCode);
            if (CollectionUtil.isEmpty(filteredTasks)) {
                continue;
            }

            // 4. 遍历当前类型的任务，尝试完成
            for (PointActivityTask task : filteredTasks) {
                PointActivity activity = activityMap.get(task.getActivityId());
                if (tryCompleteSingleTask(openId, task, activity, typeCode, taskTypeEnum, activityNameEnum)) {
                    return; // 完成首个合格任务后立即返回
                }
            }
        }
    }

    /**
     * 过滤指定活动类型下的有效任务（活动存在 + 类型匹配 + 进行中）
     */
    private List<PointActivityTask> filterValidTasks(List<PointActivityTask> allTasks, Map<Long, PointActivity> activityMap, Integer typeCode) {
        return allTasks.stream().filter(task -> {
            PointActivity activity = activityMap.get(task.getActivityId());
            return activity != null
                    && Objects.equals(activity.getActivityType(), typeCode)
                    && Objects.equals(activity.getStatus(), PointActivityStatusEnum.IN_PROGRESS.getCode());
        }).collect(Collectors.toList());
    }

    /**
     * 尝试完成单个任务，返回是否成功完成
     */
    private boolean tryCompleteSingleTask(String openId, PointActivityTask task, PointActivity activity,
                                          Integer typeCode, PointActivityTaskTypeEnum taskTypeEnum,
                                          TaskNameEnum activityNameEnum) {
        try {
            // 1. 解析频率限制
            TaskLimitTimesEnum limitEnum = parseFrequencyLimit(task);
            if (limitEnum == null) {
                return false;
            }

            // 2. 校验业务数据是否达标
            Date queryTime = getQueryStartTime(activity.getIsPermanent(), typeCode);
            if (!isTaskTargetMet(task, taskTypeEnum, limitEnum.getTime(), queryTime, activity, openId)) {
                return false;
            }

            // 3. 防重复领取：利用 TaskLimitTimesEnum 策略模式校验
            PointUserActivityTaskCompletion record = getTaskRecordInPeriod(openId, activity.getId(), task.getId(), ActivityCompletionTaskTypeEnum.ACTIVITY.getCode(), queryTime);
            int completedCount = (record != null) ? record.getCompletedCount() : 0;
            if (!limitEnum.executeCheck(completedCount)) {
                return false;
            }

            // 4. 完成任务 + 发放积分
            completeTask(openId, activity.getId(), task.getId(), ActivityCompletionTaskTypeEnum.ACTIVITY.getCode());
            pointAccountService.addPoints(openId, task.getRewardPoints().intValue(), activity.getName(),
                    null, activity.getId(), task.getId(), ActivityCompletionTaskTypeEnum.ACTIVITY.getCode(), activityNameEnum.getInfo());
            return true;
        } catch (ServiceException e) {
            if (!e.getMessage().contains("已完成") && !e.getMessage().contains("已领取")) {
                throw e;
            }
            log.warn("任务处理异常：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 解析任务频率限制配置，返回null表示配置异常（调用方应跳过该任务）
     */
    private TaskLimitTimesEnum parseFrequencyLimit(PointActivityTask task) {
        String frequencyLimitValue = task.getFrequencyLimitValue();
        if (StrUtil.isBlank(frequencyLimitValue)) {
            log.warn("任务未配置频率限制值，跳过: taskId={}", task.getId());
            return null;
        }
        TaskLimitTimesEnum limitEnum = TaskLimitTimesEnum.getByValue(frequencyLimitValue);
        if (limitEnum == null || limitEnum.getTime() == null || limitEnum.getTime() <= 0) {
            log.warn("任务配置异常，跳过处理: taskId={}", task.getId());
            return null;
        }
        return limitEnum;
    }

    /**
     * 校验任务业务目标是否达成
     * - 充值任务：实际充值金额 >= triggerValue 目标值
     * - 完成订单：实际完成次数 >= 频率限制次数
     */
    private boolean isTaskTargetMet(PointActivityTask task, PointActivityTaskTypeEnum taskTypeEnum,
                                    int targetCount, Date queryTime,
                                    PointActivity activity, String openId) {
        // 调用getActualCountByActivityType方法获取实际完成次数
        int actualCount = getActualCountByActivityType(task, activity, queryTime, openId);

        if (ObjUtil.equals(taskTypeEnum.getCode(), PointActivityTaskTypeEnum.RECHARGE_TASK.getCode())) {
            // 充值任务：triggerValue 为目标金额
            String targetValueStr = task.getTriggerValue();
            if (StrUtil.isBlank(targetValueStr)) {
                log.warn("任务未配置目标值，跳过: taskId={}", task.getId());
                return false;
            }
            int targetValue;
            try {
                targetValue = Integer.parseInt(targetValueStr);
            } catch (NumberFormatException e) {
                log.warn("任务目标值格式错误，跳过: taskId={}, value={}", task.getId(), targetValueStr);
                return false;
            }
            return actualCount >= targetValue;
        } else if (ObjUtil.equals(taskTypeEnum.getCode(), PointActivityTaskTypeEnum.COMPLETE_ORDER.getCode())) {
            // 完成订单：实际完成次数 >= 目标次数
            return actualCount >= targetCount;
        }

        // 其他任务类型（分享、浏览等）默认视为已达标
        return true;
    }

    /**
     * 检查用户是否已经完成过任何新手活动任务
     */
    private boolean checkIfUserCompletedAnyNewUserTask(String openId) {
        // 1. 查询用户所有的任务完成记录
        List<PointUserActivityTaskCompletion> records = this.list(
                Wrappers.lambdaQuery(PointUserActivityTaskCompletion.class)
                        .eq(PointUserActivityTaskCompletion::getOpenId, openId)
        );

        if (CollectionUtil.isEmpty(records)) {
            return false; // 没有记录，肯定没完成过
        }

        // 2. 获取这些记录关联的活动ID
        Set<Long> activityIdSet = records.stream()
                .map(PointUserActivityTaskCompletion::getActivityId)
                .collect(Collectors.toSet());

        // 3. 查询这些活动的详细信息，看是否有“新手活动”类型
        if (CollectionUtil.isNotEmpty(activityIdSet)) {
            List<PointActivity> activities = pointActivityService.listByIds(activityIdSet);
            return activities.stream().anyMatch(activity ->
                    PointActivityTypeEnum.NEW_USER_ACTIVITY.getCode().equals(activity.getActivityType())
            );
        }

        return false;
    }

    /**
     * 根据活动类型获取任务完成次数
     */
    private int getActualCountByActivityType(PointActivityTask task, PointActivity activity,
                                             Date queryTime, String openId) {
        switch (activity.getActivityType()) {
            case 1: // 新手活动
                return getNewHandTaskCompletionCount(task, openId);
            case 2: // 每日活动
                return getDailyTaskCompletionCount(task, openId, queryTime);
            default: // 每月活动
                return getMonthlyTaskCompletionCount(task, openId, queryTime);
        }
    }

    /**
     * 获取新手活动任务完成次数（无时间限制，只要参与就累计）
     */
    private int getNewHandTaskCompletionCount(PointActivityTask task, String openId) {
        PointUserActivityTaskCompletion completion = pointUserActivityTaskCompletionMapper.selectOne(
                new LambdaQueryWrapper<PointUserActivityTaskCompletion>()
                        .eq(PointUserActivityTaskCompletion::getOpenId, openId)
                        .eq(PointUserActivityTaskCompletion::getTaskId, task.getId())
                        .eq(PointUserActivityTaskCompletion::getActivityId, task.getActivityId())
        );

        return completion != null ? completion.getCompletedCount() : 0;
    }

    /**
     * 获取每日活动任务完成次数
     */
    private int getDailyTaskCompletionCount(PointActivityTask task, String openId, Date todayStart) {
        Date todayEnd = DateUtil.endOfDay(todayStart != null ? todayStart : new Date());

        PointUserActivityTaskCompletion completion = pointUserActivityTaskCompletionMapper.selectOne(
                new LambdaQueryWrapper<PointUserActivityTaskCompletion>()
                        .eq(PointUserActivityTaskCompletion::getOpenId, openId)
                        .eq(PointUserActivityTaskCompletion::getTaskId, task.getId())
                        .eq(PointUserActivityTaskCompletion::getActivityId, task.getActivityId())
                        .between(PointUserActivityTaskCompletion::getLastCompletedTime, todayStart, todayEnd)
        );

        return completion != null ? completion.getCompletedCount() : 0;
    }

    /**
     * 获取每月活动任务完成次数
     */
    private int getMonthlyTaskCompletionCount(PointActivityTask task, String openId, Date todayStart) {
        Date monthEnd = DateUtil.endOfMonth(todayStart != null ? todayStart : new Date());

        PointUserActivityTaskCompletion completion = pointUserActivityTaskCompletionMapper.selectOne(
                new LambdaQueryWrapper<PointUserActivityTaskCompletion>()
                        .eq(PointUserActivityTaskCompletion::getOpenId, openId)
                        .eq(PointUserActivityTaskCompletion::getTaskId, task.getId())
                        .eq(PointUserActivityTaskCompletion::getActivityId, task.getActivityId())
                        .between(PointUserActivityTaskCompletion::getLastCompletedTime, todayStart, monthEnd)
        );

        return completion != null ? completion.getCompletedCount() : 0;
    }

}