package com.ylx.point.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
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.massage.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.TaskNameEnum;
import com.ylx.point.enums.PointActivityStatusEnum;
import com.ylx.point.enums.PointActivityTaskTypeEnum;
import com.ylx.point.enums.PointActivityTypeEnum;
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.function.Function;
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. 任务校验逻辑
        if (ObjectUtil.notEqual(PointActivityTypeEnum.DAILY_ACTIVITY.getCode(), activityType) ||
                ObjectUtil.notEqual(PointActivityTypeEnum.NEW_USER_ACTIVITY.getCode(), activityType) ||
                ObjectUtil.notEqual(PointActivityTypeEnum.MONTHLY_ACTIVITY.getCode(), 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.getTaskRecord(openId, activityId, taskId, taskTypeEnum.getCode());
            if (record != null && 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("任务未完成，无法领取奖励");
        }
    }

    /**
     * 根据任务类型获取任务名称 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());
        }
        return StartTime;
    }

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

    /**
     * 获取任务完成记录
     */
    private PointUserActivityTaskCompletion getTaskRecord(String openId, Long activityId, Long taskId, Integer taskType) {
        return this.getOne(Wrappers.lambdaQuery(PointUserActivityTaskCompletion.class)
                .eq(PointUserActivityTaskCompletion::getOpenId, openId)
                .eq(PointUserActivityTaskCompletion::getActivityId, activityId)
                .eq(PointUserActivityTaskCompletion::getTaskId, taskId)
                .eq(PointUserActivityTaskCompletion::getTaskType, taskType)
        );
    }

    /**
     * 通用优先级任务完成方法
     */
    private void completeTaskByPriority(String openId, TaskNameEnum activityNameEnum,
                                        PointActivityTaskTypeEnum taskTypeEnum,
                                        Function<Date, Integer> countFunction) {
        // 批量查询所有有效任务
        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;
        }

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

        // 按优先级处理活动类型
        for (Integer typeCode : ACTIVITY_TYPE_PRIORITY) {
            // 过滤当前类型的有效任务
            List<PointActivityTask> taskList = 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());

            if (CollectionUtil.isEmpty(taskList)) {
                continue;
            }

            // 执行任务
            for (PointActivityTask task : taskList) {
                try {
                    PointActivity activity = activityMap.get(task.getActivityId());
                    int targetCount = Integer.parseInt(task.getTriggerValue());
                    Date queryTime = getQueryStartTime(activity.getIsPermanent(), typeCode);
                    int completed = countFunction.apply(queryTime);

                    if (completed < targetCount) {
                        continue;
                    }

                    // 防重复领取
                    PointUserActivityTaskCompletion record = getTaskRecord(openId, activity.getId(), task.getId(), taskTypeEnum.getCode());
                    if (record != null && record.getCompletedCount() >= targetCount) {
                        continue;
                    }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeOrderTaskByPriority(String openId) {
        completeTaskByPriority(openId, TaskNameEnum.COMPLETE_ORDER,
                PointActivityTaskTypeEnum.COMPLETE_ORDER,
                new Function<Date, Integer>() {
                    @Override
                    public Integer apply(Date queryTime) {
                        return orderService.countCompletedOrders(openId, queryTime);
                    }
                });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completeRechargeTaskByPriority(String openId) {
        completeTaskByPriority(openId, TaskNameEnum.RECHARGE_TASK,
                PointActivityTaskTypeEnum.RECHARGE_TASK,
                new Function<Date, Integer>() {
                    @Override
                    public Integer apply(Date queryTime) {
                        return rechargeService.countSuccessRecharges(openId, queryTime);
                    }
                });
    }
}