import com.red.circle.OtherServiceApplication;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.order.inner.model.enums.MonthlyRechargeType;
import com.red.circle.other.app.service.activity.ActivityRechargeTicketService;
import com.red.circle.other.infra.database.rds.dao.activity.UserActivityRechargeDAO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.test.context.junit4.SpringRunner;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@SpringBootTest(classes = OtherServiceApplication.class)
@RunWith(SpringRunner.class)
public class RedisTest {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ActivityRechargeTicketService activityRechargeTicketService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private UserActivityRechargeDAO userActivityRechargeDAO;

    // 常量定义（与业务代码保持一致）
    private static final Long FIXED_ACTIVITY_ID = -1L;
    private static final long TICKET_THRESHOLD = 100000L; // 每10000发一张券，请根据实际值修改

    @Test
    public void testRedis(){
        setExpireTimeForAziziKeys();
    }

    public void setExpireTimeForAziziKeys() {
        String pattern = "AZIZI_SEVEN_CHECK_IN:*";
        long expireTime = 365; // 天数

        // 使用 scan 遍历匹配的 key
        ScanOptions options = ScanOptions.scanOptions()
                .match(pattern)
                .count(100) // 每次扫描100个
                .build();

        redisTemplate.execute((RedisCallback<Object>) connection -> {
            Cursor<byte[]> cursor = connection.scan(options);
            while (cursor.hasNext()) {
                String key = new String(cursor.next());
                System.out.println();
                redisTemplate.expire(key, expireTime, TimeUnit.DAYS);
            }
            cursor.close();
            return null;
        });
    }

    @Test
    public void testRedis2(){
        // 春节活动 已结束
//        activityRechargeTicketService.accumulatedRechargeAndAddTicket(1957345312961527809L, 80000L, MonthlyRechargeType.UNDEFINED);
    }

    /**
     * 查找脏数据用户ID
     * 条件：Redis中记录的threshold值 > 数据库中的totalWinCoins
     */
    @Test
    public void findDirtyDataUsers() {
        System.out.println("==========开始查找脏数据用户==========");
        System.out.println("活动ID: " + FIXED_ACTIVITY_ID);
        System.out.println("券阈值: " + TICKET_THRESHOLD);
        System.out.println();

        String pattern = String.format("lucky:draw:threshold:*:%s", FIXED_ACTIVITY_ID);
        List<Long> dirtyUserIds = new ArrayList<>();
        List<String> dirtyDetails = new ArrayList<>();

        // 使用 scan 遍历匹配的 key
        ScanOptions options = ScanOptions.scanOptions()
                .match(pattern)
                .count(1000) // 每次扫描1000个
                .build();

        redisTemplate.execute((RedisCallback<Object>) connection -> {
            Cursor<byte[]> cursor = connection.scan(options);
            int totalCount = 0;
            int dirtyCount = 0;

            while (cursor.hasNext()) {
                String key = new String(cursor.next());
                totalCount++;

                try {
                    // 从key中提取userId
                    // key格式: lucky:draw:threshold:{userId}:{activityId}
                    String[] parts = key.split(":");
                    if (parts.length >= 4) {
                        Long userId = Long.parseLong(parts[3]);

                        // 获取Redis中的threshold值
                        String thresholdStr = redisService.getString(key);
                        if (thresholdStr == null) {
                            continue;
                        }
                        long redisThreshold = Long.parseLong(thresholdStr);

                        // 获取数据库中的实际充值总额
                        BigDecimal totalWinCoins = userActivityRechargeDAO.getUserTotalAmount(
                                userId, FIXED_ACTIVITY_ID, null);
                        long dbTotal = (totalWinCoins != null) ? totalWinCoins.longValue() : 0L;

                        // 检查是否为脏数据：Redis中的值 > 数据库中的值
                        if (redisThreshold > dbTotal) {
                            dirtyCount++;
                            dirtyUserIds.add(userId);
                            
                            String detail = String.format(
                                    "脏数据 #%d - 用户ID: %d, Redis阈值: %d, 数据库总额: %d, 差额: %d",
                                    dirtyCount, userId, redisThreshold, dbTotal, (redisThreshold - dbTotal)
                            );
                            dirtyDetails.add(detail);
                            System.out.println(detail);
                        }

                        // 每处理100条打印进度
                        if (totalCount % 100 == 0) {
                            System.out.println("已扫描: " + totalCount + " 条记录, 发现脏数据: " + dirtyCount + " 条");
                        }
                    }
                } catch (Exception e) {
                    System.err.println("处理key失败: " + key + ", 错误: " + e.getMessage());
                }
            }
            cursor.close();

            System.out.println();
            System.out.println("==========扫描完成==========");
            System.out.println("总扫描记录数: " + totalCount);
            System.out.println("脏数据记录数: " + dirtyCount);
            System.out.println();

            return null;
        });

        // 输出汇总结果
        if (!dirtyUserIds.isEmpty()) {
            System.out.println("==========脏数据用户ID列表==========");
            System.out.println(dirtyUserIds);
            System.out.println();

            System.out.println("==========脏数据详情==========");
            for (String detail : dirtyDetails) {
                System.out.println(detail);
            }
            System.out.println();

            System.out.println("==========SQL修复语句（仅供参考）==========");
            System.out.println("-- 可以通过以下方式清理Redis中的脏数据:");
            for (Long userId : dirtyUserIds) {
                String key = String.format("lucky:draw:threshold:%s:%s", userId, FIXED_ACTIVITY_ID);
                System.out.println("-- DEL " + key);
            }
        } else {
            System.out.println("未发现脏数据！");
        }
    }

    /**
     * 批量修复脏数据（慎用！）
     * 将Redis中的threshold值重置为数据库中的实际值
     */
    @Test
    public void fixDirtyData() {
        System.out.println("==========开始修复脏数据==========");
        System.out.println("警告：此操作将修改Redis数据，请确认后执行！");
        System.out.println();

        String pattern = String.format("lucky:draw:threshold:*:%s", FIXED_ACTIVITY_ID);
        
        ScanOptions options = ScanOptions.scanOptions()
                .match(pattern)
                .count(1000)
                .build();

        redisTemplate.execute((RedisCallback<Object>) connection -> {
            Cursor<byte[]> cursor = connection.scan(options);
            int fixedCount = 0;

            while (cursor.hasNext()) {
                String key = new String(cursor.next());

                try {
                    String[] parts = key.split(":");
                    if (parts.length >= 4) {
                        Long userId = Long.parseLong(parts[3]);

                        String thresholdStr = redisService.getString(key);
                        if (thresholdStr == null) {
                            continue;
                        }
                        long redisThreshold = Long.parseLong(thresholdStr);

                        BigDecimal totalWinCoins = userActivityRechargeDAO.getUserTotalAmount(
                                userId, FIXED_ACTIVITY_ID, null);
                        long dbTotal = (totalWinCoins != null) ? totalWinCoins.longValue() : 0L;

                        // 如果是脏数据，修复为数据库中的实际值
                        if (redisThreshold > dbTotal) {
                            // 计算应该设置的正确threshold值（向下取整到阈值倍数）
                            long correctThreshold = 0;
                            
                            redisService.setString(key, String.valueOf(correctThreshold));
                            fixedCount++;
                            
                            System.out.println(String.format(
                                    "已修复 - 用户ID: %d, 原值: %d, 新值: %d, 数据库总额: %d",
                                    userId, redisThreshold, correctThreshold, dbTotal
                            ));
                        }
                    }
                } catch (Exception e) {
                    System.err.println("修复key失败: " + key + ", 错误: " + e.getMessage());
                }
            }
            cursor.close();

            System.out.println();
            System.out.println("==========修复完成==========");
            System.out.println("共修复: " + fixedCount + " 条脏数据");

            return null;
        });
    }

}
