package com.aps.demo;

import com.aps.common.util.redis.RedisUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
public class RedisUtilsTest {

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @BeforeEach
    void setUp() {
        // 清理可能存在的测试数据
        Set<String> keys = redisTemplate.keys("jvs:test:*");
        if (keys != null && !keys.isEmpty()) {
            redisTemplate.delete(keys);
        }
    }

    @Test
    public void testSetAndGet() {
        String key = "test:setAndGet";
        String value = "testValue";

        // 测试设置值
        Boolean setResult = redisUtils.set(key, value);
        assertTrue(setResult, "设置值应该成功");

        // 测试获取值
        Object getResult = redisUtils.get(key);
        assertEquals(value, getResult, "获取的值应该与设置的值相同");
        System.out.println("获取的值：" + getResult);

    }

    @Test
    public void testSetWithExpire() {
        String key = "test:setWithExpire";
        String value = "testValue";
        Long expireTime = 5L;

        // 测试设置带过期时间的值
        Boolean setResult = redisUtils.set(key, value, expireTime);
        assertTrue(setResult, "设置带过期时间的值应该成功");

        // 验证值存在
        Object getResult = redisUtils.get(key);
        assertEquals(value, getResult, "获取的值应该与设置的值相同");

        // 验证过期时间
        Long ttl = redisUtils.getExpire(key);
        assertTrue(ttl > 0 && ttl <= expireTime, "过期时间应该在预期范围内");
    }

    @Test
    public void testExistsAndHasKey() {
        String key = "test:exists";
        String value = "testValue";

        // 初始状态下key不存在
        assertFalse(redisUtils.exists(key), "初始状态下key不应该存在");
        assertFalse(redisUtils.hasKey(key), "初始状态下key不应该存在");

        // 设置值后key应该存在
        redisUtils.set(key, value);
        assertTrue(redisUtils.exists(key), "设置值后key应该存在");
        assertTrue(redisUtils.hasKey(key), "设置值后key应该存在");
    }

    @Test
    public void testDel() {
        String key = "test:del";
        String value = "testValue";

        // 设置值
        redisUtils.set(key, value);
        assertTrue(redisUtils.exists(key), "设置值后key应该存在");

        // 删除值
        redisUtils.del(key);
        assertFalse(redisUtils.exists(key), "删除后key不应该存在");

        // 测试批量删除
        String key1 = "test:del1";
        String key2 = "test:del2";
        redisUtils.set(key1, value);
        redisUtils.set(key2, value);
        assertTrue(redisUtils.exists(key1), "设置值后key1应该存在");
        assertTrue(redisUtils.exists(key2), "设置值后key2应该存在");

        redisUtils.del(key1, key2);
        assertFalse(redisUtils.exists(key1), "批量删除后key1不应该存在");
        assertFalse(redisUtils.exists(key2), "批量删除后key2不应该存在");
    }

    @Test
    public void testExpire() {
        String key = "test:expire";
        String value = "testValue";
        int expireTime = 10;

        redisUtils.set(key, value);
        redisUtils.expire(key, expireTime, TimeUnit.SECONDS);

        Long ttl = redisUtils.getExpire(key);
        assertTrue(ttl > 0 && ttl <= expireTime, "过期时间应该在预期范围内");
    }

    @Test
    public void testKeys() {
        String key1 = "test:keys1";
        String key2 = "test:keys2";
        String value = "testValue";

        redisUtils.set(key1, value);
        redisUtils.set(key2, value);

        Set<String> keys = redisUtils.keys("test:keys*");
        assertNotNull(keys, "返回的keys不应该为null");
        assertTrue(keys.contains("jvs:test:keys1"), "应该包含key1");
        assertTrue(keys.contains("jvs:test:keys2"), "应该包含key2");
    }

    @Test
    public void testIncrAndDecr() {
        String key = "test:incrdecr";
        Long initialValue = 10L;
        Long delta = 5L;

        redisUtils.set(key, initialValue);

        // 测试递增
        Long incrResult = redisUtils.incr(key, delta);
        assertEquals(initialValue + delta, incrResult, "递增结果应该正确");

        // 测试递减
        Long decrResult = redisUtils.decr(key, delta);
        assertEquals(initialValue, decrResult, "递减结果应该正确");
    }

    @Test
    public void testHashSetAndGet() {
        String key = "test:hash";
        String item1 = "item1";
        String item2 = "item2";
        String value1 = "value1";
        String value2 = "value2";

        // 测试单个hash设置和获取
        Boolean hsetResult = redisUtils.hset(key, item1, value1);
        assertTrue(hsetResult, "Hash设置应该成功");

        Object hgetResult = redisUtils.hget(key, item1);
        assertEquals(value1, hgetResult, "Hash获取的值应该正确");

        // 测试多个hash设置和获取
        Map<String, Object> map = new HashMap<>();
        map.put(item1, value1);
        map.put(item2, value2);

        Boolean hmsetResult = redisUtils.hmset(key, map);
        assertTrue(hmsetResult, "批量Hash设置应该成功");

        Map<Object, Object> hmgetResult = redisUtils.hmget(key);
        assertNotNull(hmgetResult, "批量Hash获取结果不应该为null");
        assertEquals(value1, hmgetResult.get(item1), "Hash获取的值应该正确");
        assertEquals(value2, hmgetResult.get(item2), "Hash获取的值应该正确");

        // 测试hash是否存在
        Boolean hHasKeyResult = redisUtils.hHasKey(key, item1);
        assertTrue(hHasKeyResult, "Hash key应该存在");
    }

    @Test
    public void testHashDelAndIncr() {
        String key = "test:hashdel";
        String item = "item";
        String value = "10";

        redisUtils.hset(key, item, value);

        // 测试hash删除
        redisUtils.hdel(key, item);
        Boolean hHasKeyResult = redisUtils.hHasKey(key, item);
        assertFalse(hHasKeyResult, "删除后Hash key不应该存在");

        // 测试hash递增
        String incrItem = "incrItem";
        Double incrValue = 5.0;
        Double hincrResult = redisUtils.hincr(key, incrItem, incrValue);
        assertEquals(incrValue, hincrResult, "Hash递增结果应该正确");

        // 测试hash递减
        Double decrValue = 3.0;
        Double hdecrResult = redisUtils.hdecr(key, incrItem, decrValue);
        assertEquals(incrValue - decrValue, hdecrResult, "Hash递减结果应该正确");
    }

    @Test
    public void testSetOperations() {
        String key = "test:set";
        String value1 = "value1";
        String value2 = "value2";

        // 测试添加set元素
        Long sSetResult = redisUtils.sSet(key, value1, value2);
        assertEquals(2, sSetResult, "应该成功添加2个元素");

        // 测试set大小
        Long sGetSizeResult = redisUtils.sGetSetSize(key);
        assertEquals(2, sGetSizeResult, "Set大小应该为2");

        // 测试元素是否存在于set中
        Boolean sHasKeyResult = redisUtils.sHasKey(key, value1);
        assertTrue(sHasKeyResult, "value1应该存在于set中");

        // 测试获取set所有元素
        Set<Object> sGetResult = redisUtils.sGet(key);
        assertNotNull(sGetResult, "Set结果不应该为null");
        assertTrue(sGetResult.contains(value1), "Set应该包含value1");
        assertTrue(sGetResult.contains(value2), "Set应该包含value2");

        // 测试从set中移除元素
        Long setRemoveResult = redisUtils.setRemove(key, value1);
        assertEquals(1, setRemoveResult, "应该成功移除1个元素");

        sGetSizeResult = redisUtils.sGetSetSize(key);
        assertEquals(1, sGetSizeResult, "移除元素后Set大小应该为1");
    }

    @Test
    public void testListOperations() {
        String key = "test:list";
        String value1 = "value1";
        String value2 = "value2";
        String value3 = "value3";

        // 测试往list头部插入值
        Boolean lSetListResult = redisUtils.lSetList(key, value1);
        assertTrue(lSetListResult, "往list头部插入值应该成功");

        // 测试往list尾部插入值
        Boolean lSetListRightResult = redisUtils.lSetListRight(key, value2);
        assertTrue(lSetListRightResult, "往list尾部插入值应该成功");

        // 测试获取list长度
        Long lGetListSizeResult = redisUtils.lGetListSize(key);
        assertEquals(2, lGetListSizeResult, "List长度应该为2");

        // 测试通过索引获取list中的值
        Object lGetIndexResult = redisUtils.lGetIndex(key, 0L);
        assertEquals(value1, lGetIndexResult, "索引0的值应该是value1");

        lGetIndexResult = redisUtils.lGetIndex(key, -1L);
        assertEquals(value2, lGetIndexResult, "索引-1的值应该是value2");

        // 测试获取list缓存内容
        List<Object> lGetResult = redisUtils.lGet(key, 0, -1);
        assertNotNull(lGetResult, "List结果不应该为null");
        assertEquals(2, lGetResult.size(), "List大小应该为2");
        assertEquals(value1, lGetResult.get(0), "第一个元素应该是value1");
        assertEquals(value2, lGetResult.get(1), "第二个元素应该是value2");

        // 测试批量设置list
        List<Object> values = Arrays.asList(value1, value2, value3);
        Boolean lSetListBatchResult = redisUtils.lSetList(key, values);
        assertTrue(lSetListBatchResult, "批量设置list应该成功");

        lGetListSizeResult = redisUtils.lGetListSize(key);
        assertEquals(3, lGetListSizeResult, "批量设置后List长度应该为3");

        // 测试根据索引修改list中的某条数据
        String newValue = "newValue";
        Boolean lUpdateIndexResult = redisUtils.lUpdateIndex(key, 0L, newValue);
        assertTrue(lUpdateIndexResult, "根据索引修改list数据应该成功");

        lGetIndexResult = redisUtils.lGetIndex(key, 0L);
        assertEquals(newValue, lGetIndexResult, "索引0的值应该被更新");

        // 测试移除N个值为value的元素
        Long lRemoveResult = redisUtils.lRemove(key, 1L, value2);
        assertEquals(1, lRemoveResult, "应该成功移除1个元素");
    }

    @Test
    public void testPrefix() {
        String originalPrefix = RedisUtils.getPrefix();
        String newPrefix = "test_prefix:";
        
        // 修改前缀
        RedisUtils.setPrefix(newPrefix);
        assertEquals(newPrefix, RedisUtils.getPrefix(), "前缀应该被正确设置");
        
        // 测试使用新前缀的操作
        String key = "test:prefix";
        String value = "testValue";
        RedisUtils redisUtilsWithoutAutowired = new RedisUtils();
        
        // 恢复原始前缀
        RedisUtils.setPrefix(originalPrefix);
    }
}