package shop.alien.job.second;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import shop.alien.entity.second.SecondUserCredit;
import shop.alien.entity.second.SecondUserCreditDateRecord;
import shop.alien.entity.second.SecondUserCreditRecord;
import shop.alien.mapper.second.SecondUserCreditDateRecordMapper;
import shop.alien.mapper.second.SecondUserCreditMapper;
import shop.alien.mapper.second.SecondUserCreditRecordMapper;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class SecondUserCreditJob {

    private final SecondUserCreditRecordMapper secondUserCreditRecordMapper;
    private final SecondUserCreditDateRecordMapper secondUserCreditDateRecordMapper;
    private final SecondUserCreditMapper secondUserCreditMapper;

    @XxlJob("sumUserCredit")
    public void sumUserCredit() {
        log.info("开始执行用户积分任务");
        // 计算每个用户从有数据的第一天开始，逐日计算积分
        // 如果表中已经有该用户对应日期的数据，则跳过不计算
        // 存到数据库second_user_credit_date_record表中

        try {
            // 获取当天的开始时间（作为计算的结束日期）
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            Date todayStart = calendar.getTime();

            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            calendar.set(Calendar.MILLISECOND, 999);
            Date todayEnd = calendar.getTime();

            log.info("开始处理用户积分，计算截止日期：{}", todayStart);

            // 获取所有有积分记录的用户ID
            LambdaQueryWrapper<SecondUserCreditRecord> userQuery = new LambdaQueryWrapper<>();
            userQuery.select(SecondUserCreditRecord::getUserId)
                    .eq(SecondUserCreditRecord::getDeleteFlag, 0)
                    .groupBy(SecondUserCreditRecord::getUserId);
            List<SecondUserCreditRecord> userRecords = secondUserCreditRecordMapper.selectList(userQuery);
            Set<Integer> allUserIds = userRecords.stream()
                    .map(SecondUserCreditRecord::getUserId)
                    .collect(Collectors.toSet());

            log.info("找到有积分记录的用户总数：{}", allUserIds.size());

            int successCount = 0;
            int skipCount = 0;
            int failCount = 0;

            // 为每个用户从有数据的第一天开始计算
            for (Integer userId : allUserIds) {
                try {
                    // 查找用户最早的积分记录日期
                    LambdaQueryWrapper<SecondUserCreditRecord> firstRecordQuery = new LambdaQueryWrapper<>();
                    firstRecordQuery.eq(SecondUserCreditRecord::getUserId, userId)
                            .eq(SecondUserCreditRecord::getDeleteFlag, 0)
                            .orderByAsc(SecondUserCreditRecord::getCreatedTime)
                            .last("LIMIT 1");
                    SecondUserCreditRecord firstRecord = secondUserCreditRecordMapper.selectOne(firstRecordQuery);

                    if (firstRecord == null || firstRecord.getCreatedTime() == null) {
                        log.debug("用户 {} 没有找到有效的积分记录，跳过", userId);
                        continue;
                    }

                    // 获取用户最早记录日期（作为第一天）
                    Date firstRecordDate = firstRecord.getCreatedTime();
                    Calendar firstCal = Calendar.getInstance();
                    firstCal.setTime(firstRecordDate);
                    firstCal.set(Calendar.HOUR_OF_DAY, 0);
                    firstCal.set(Calendar.MINUTE, 0);
                    firstCal.set(Calendar.SECOND, 0);
                    firstCal.set(Calendar.MILLISECOND, 0);
                    Date firstDate = firstCal.getTime();

                    log.debug("用户 {} 最早记录日期：{}，开始逐日计算", userId, firstDate);

                    // 查询该用户已有的日期记录（避免重复计算）
                    LambdaQueryWrapper<SecondUserCreditDateRecord> existingQuery = new LambdaQueryWrapper<>();
                    existingQuery.eq(SecondUserCreditDateRecord::getUserId, userId)
                            .eq(SecondUserCreditDateRecord::getDeleteFlag, 0)
                            .ge(SecondUserCreditDateRecord::getRecordDate, firstDate)
                            .le(SecondUserCreditDateRecord::getRecordDate, todayEnd)
                            .orderByAsc(SecondUserCreditDateRecord::getRecordDate);
                    List<SecondUserCreditDateRecord> existingRecords = secondUserCreditDateRecordMapper.selectList(existingQuery);
                    
                    // 构建已存在日期的Map（用于快速查找和判断）
                    Map<String, Integer> existingDatesMap = new HashMap<>();
                    for (SecondUserCreditDateRecord record : existingRecords) {
                        Calendar cal = Calendar.getInstance();
                        cal.setTime(record.getRecordDate());
                        String dateStr = String.format("%d-%02d-%02d",
                            cal.get(Calendar.YEAR),
                            cal.get(Calendar.MONTH) + 1,
                            cal.get(Calendar.DAY_OF_MONTH));
                        existingDatesMap.put(dateStr, record.getTotalPoints());
                    }

                    // 查询该用户所有的积分记录（用于计算每天的总积分）
                    LambdaQueryWrapper<SecondUserCreditRecord> allRecordsQuery = new LambdaQueryWrapper<>();
                    allRecordsQuery.eq(SecondUserCreditRecord::getUserId, userId)
                            .eq(SecondUserCreditRecord::getDeleteFlag, 0)
                            .ge(SecondUserCreditRecord::getCreatedTime, firstDate)
                            .le(SecondUserCreditRecord::getCreatedTime, todayEnd)
                            .orderByAsc(SecondUserCreditRecord::getCreatedTime);
                    List<SecondUserCreditRecord> allUserRecords = secondUserCreditRecordMapper.selectList(allRecordsQuery);

                    // 将积分记录按日期分组
                    Map<String, Integer> dailyPointsMap = allUserRecords.stream()
                            .collect(Collectors.groupingBy(
                                    record -> {
                                        Calendar cal = Calendar.getInstance();
                                        cal.setTime(record.getCreatedTime());
                                        return String.format("%d-%02d-%02d",
                                            cal.get(Calendar.YEAR),
                                            cal.get(Calendar.MONTH) + 1,
                                            cal.get(Calendar.DAY_OF_MONTH));
                                    },
                                    Collectors.summingInt(SecondUserCreditRecord::getPoints)
                            ));

                    // 从第一天开始，逐日计算到当天
                    Calendar currentCal = Calendar.getInstance();
                    currentCal.setTime(firstDate);
                    Calendar endCal = Calendar.getInstance();
                    endCal.setTime(todayEnd);
                    endCal.set(Calendar.HOUR_OF_DAY, 23);
                    endCal.set(Calendar.MINUTE, 59);
                    endCal.set(Calendar.SECOND, 59);
                    endCal.set(Calendar.MILLISECOND, 999);

                    // 从第一天开始，逐日计算
                    int accumulatedPoints = 0;
                    
                    while (!currentCal.after(endCal)) {
                        Date currentDate = currentCal.getTime();
                        String currentDateStr = String.format("%d-%02d-%02d",
                            currentCal.get(Calendar.YEAR),
                            currentCal.get(Calendar.MONTH) + 1,
                            currentCal.get(Calendar.DAY_OF_MONTH));

                        // 检查该日期是否已存在记录，如果存在则跳过
                        if (existingDatesMap.containsKey(currentDateStr)) {
                            // 已存在记录，更新累积积分为该日期的积分值，用于后续日期的计算
                            accumulatedPoints = existingDatesMap.get(currentDateStr);
                            skipCount++;
                            currentCal.add(Calendar.DAY_OF_YEAR, 1);
                            continue;
                        }

                        // 当天有积分变动，累加到总积分
                        Integer dayPoints = dailyPointsMap.getOrDefault(currentDateStr, 0);
                        accumulatedPoints += dayPoints;

                        // 创建该日期的积分记录
                        SecondUserCreditDateRecord dateRecord = new SecondUserCreditDateRecord();
                        dateRecord.setUserId(userId);
                        dateRecord.setRecordDate(currentDate);
                        dateRecord.setTotalPoints(accumulatedPoints);
                        dateRecord.setDeleteFlag(0);
                        dateRecord.setCreatedTime(new Date());
                        dateRecord.setUpdatedTime(new Date());

                        secondUserCreditDateRecordMapper.insert(dateRecord);
                        successCount++;

                        log.debug("用户 {} 日期 {} 积分记录已生成，当天变动：{}，累计总积分：{}",
                                userId, currentDateStr, dayPoints, accumulatedPoints);

                        // 移动到下一天
                        currentCal.add(Calendar.DAY_OF_YEAR, 1);
                    }

                } catch (Exception e) {
                    log.error("处理用户积分记录失败，userId={}", userId, e);
                    failCount++;
                }
            }

            log.info("用户积分任务执行完成，成功：{}，跳过：{}，失败：{}", successCount, skipCount, failCount);

        } catch (Exception e) {
            log.error("执行用户积分任务失败", e);
            throw e;
        }
    }

    @XxlJob("rewardNoViolationUsers")
    public void rewardNoViolationUsers() {
        log.info("开始执行无违规奖励任务");
        // 查询用户当天有没有扣分，没有扣分就加5分
        // 若今日无违规,奖励会在今日凌晨12:59:59发放

        try {
            // 获取当天的开始时间和结束时间
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            Date todayStart = calendar.getTime();

            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            calendar.set(Calendar.MILLISECOND, 999);
            Date todayEnd = calendar.getTime();

            log.info("开始处理无违规奖励，日期范围：{} 至 {}", todayStart, todayEnd);

            // 获取所有有积分记录的用户ID
            LambdaQueryWrapper<SecondUserCreditRecord> userQuery = new LambdaQueryWrapper<>();
            userQuery.select(SecondUserCreditRecord::getUserId)
                    .eq(SecondUserCreditRecord::getDeleteFlag, 0)
                    .groupBy(SecondUserCreditRecord::getUserId);
            List<SecondUserCreditRecord> userRecords = secondUserCreditRecordMapper.selectList(userQuery);
            Set<Integer> allUserIds = userRecords.stream()
                    .map(SecondUserCreditRecord::getUserId)
                    .collect(Collectors.toSet());

            log.info("找到有积分记录的用户总数：{}", allUserIds.size());

            int rewardCount = 0;
            int skipCount = 0;
            int failCount = 0;

            // 为每个用户检查当天是否有扣分
            for (Integer userId : allUserIds) {
                try {
                    // 查询用户当天是否有扣分记录（points < 0）
                    LambdaQueryWrapper<SecondUserCreditRecord> deductionQuery = new LambdaQueryWrapper<>();
                    deductionQuery.eq(SecondUserCreditRecord::getUserId, userId)
                            .eq(SecondUserCreditRecord::getDeleteFlag, 0)
                            .lt(SecondUserCreditRecord::getPoints, 0)  // 扣分记录（负数）
                            .ge(SecondUserCreditRecord::getCreatedTime, todayStart)
                            .le(SecondUserCreditRecord::getCreatedTime, todayEnd);
                    long deductionCount = secondUserCreditRecordMapper.selectCount(deductionQuery);

                    if (deductionCount > 0) {
                        // 当天有扣分，跳过
                        log.debug("用户 {} 当天有扣分记录，跳过奖励", userId);
                        skipCount++;
                        continue;
                    }

                    // 检查今天是否已经发放过奖励（避免重复发放）
                    LambdaQueryWrapper<SecondUserCreditRecord> rewardQuery = new LambdaQueryWrapper<>();
                    rewardQuery.eq(SecondUserCreditRecord::getUserId, userId)
                            .eq(SecondUserCreditRecord::getDeleteFlag, 0)
                            .eq(SecondUserCreditRecord::getPoints, 5)  // 奖励5分
                            .eq(SecondUserCreditRecord::getPointsType, 10)  // 使用10作为无违规奖励类型
                            .ge(SecondUserCreditRecord::getCreatedTime, todayStart)
                            .le(SecondUserCreditRecord::getCreatedTime, todayEnd);
                    long existingRewardCount = secondUserCreditRecordMapper.selectCount(rewardQuery);

                    if (existingRewardCount > 0) {
                        // 今天已经发放过奖励，跳过
                        log.debug("用户 {} 今天已经发放过无违规奖励，跳过", userId);
                        skipCount++;
                        continue;
                    }

                    // 用户当天没有扣分，发放5分奖励
                    // 1. 更新用户积分（使用累加方式）
                    LambdaQueryWrapper<SecondUserCredit> creditQuery = new LambdaQueryWrapper<>();
                    creditQuery.eq(SecondUserCredit::getUserId, userId)
                            .eq(SecondUserCredit::getDeleteFlag, 0);
                    SecondUserCredit userCredit = secondUserCreditMapper.selectOne(creditQuery);

                    if (userCredit == null) {
                        // 如果用户没有积分记录，先创建初始记录（0分）
                        userCredit = new SecondUserCredit();
                        userCredit.setUserId(userId);
                        userCredit.setUserPoints(userCredit.getUserPoints() + 5);
                        userCredit.setDeleteFlag(0);
                        userCredit.setCreatedTime(new Date());
                        userCredit.setUpdatedTime(new Date());
                        secondUserCreditMapper.insert(userCredit);
                    }
                    
                    // 2. 查询用户最新的一条积分记录，获取current_score_count（在更新积分之前查询）
                    LambdaQueryWrapper<SecondUserCreditRecord> latestRecordQuery = new LambdaQueryWrapper<>();
                    latestRecordQuery.eq(SecondUserCreditRecord::getUserId, userId)
                            .eq(SecondUserCreditRecord::getDeleteFlag, 0)
                            .orderByDesc(SecondUserCreditRecord::getCreatedTime)
                            .last("LIMIT 1");
                    SecondUserCreditRecord latestRecord = secondUserCreditRecordMapper.selectOne(latestRecordQuery);
                    
                    // 计算当前总积分：最新记录的current_score_count + 5分
                    Integer currentScoreCount;
                    if (latestRecord != null && latestRecord.getCurrentScoreCount() != null) {
                        // 有历史记录，累加5分
                        currentScoreCount = latestRecord.getCurrentScoreCount() + 5;
                    } else {
                        // 如果没有历史记录，从用户积分表中获取当前积分，然后加5
                        if (userCredit != null && userCredit.getUserPoints() != null) {
                            currentScoreCount = userCredit.getUserPoints() + 5;
                        } else {
                            currentScoreCount = 5;  // 默认值
                        }
                    }

                    // 3. 使用累加方式更新积分
                    secondUserCreditMapper.updatePointsByUserId(userId, 5);

                    // 4. 创建积分记录
                    SecondUserCreditRecord rewardRecord = new SecondUserCreditRecord();
                    rewardRecord.setUserId(userId);
                    rewardRecord.setPoints(5);
                    rewardRecord.setPointsType(10);  // 10表示无违规奖励
                    rewardRecord.setCurrentScoreCount(currentScoreCount);
                    rewardRecord.setDeleteFlag(0);
                    rewardRecord.setCreatedTime(new Date());
                    rewardRecord.setUpdatedTime(new Date());
                    secondUserCreditRecordMapper.insert(rewardRecord);

                    rewardCount++;
                    log.info("用户 {} 当天无违规，已发放5分奖励", userId);

                } catch (Exception e) {
                    log.error("处理用户无违规奖励失败，userId={}", userId, e);
                    failCount++;
                }
            }

            log.info("无违规奖励任务执行完成，奖励：{}，跳过：{}，失败：{}", rewardCount, skipCount, failCount);

        } catch (Exception e) {
            log.error("执行无违规奖励任务失败", e);
            throw e;
        }
    }

}
