package com.css.simulation.resource.video.configuration.redis;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class CustomRedisClient {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    //* -------------------------------- 基本操作 --------------------------------

    public Set<String> keys(String pattern) {
        return stringRedisTemplate.keys(pattern);
    }

    public String get(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    public void set(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }

    public void flushdb() {
        Set<String> keys = stringRedisTemplate.keys("*");
        if (keys != null && keys.size() != 0) {
            stringRedisTemplate.delete(keys);
        }
    }

    public void delete(String key) {
        stringRedisTemplate.delete(key);
    }

    /**
     * 加值
     */
    public long increment(String key, long number) {
        final Long increment = stringRedisTemplate.opsForValue().increment(key, number);
        if (increment == null) {
            throw new RuntimeException("key " + key + " 增量计数报错。");
        }
        return increment;
    }

    /**
     * 减值
     */
    public void decrement(String key, long number) {
        stringRedisTemplate.opsForValue().decrement(key, number);
    }


    //* -------------------------------- 分布式锁 --------------------------------

    /**
     * 加锁，有阻塞
     *
     * @param timeout 间隔多久获取一次锁
     * @param expire  锁的过期时间，防止程序崩溃后无法释放锁
     */
    @SneakyThrows
    public void lock(String name, long timeout, long expire) {
        Boolean success = false;
        while (!success) {
            success = tryLock(name, expire);
            TimeUnit.MILLISECONDS.sleep(timeout);
        }
    }

    /**
     * 尝试加锁，无阻塞
     */
    public Boolean tryLock(String name, long expire) {
        return stringRedisTemplate.opsForValue().setIfAbsent(name, "None", Duration.ofMillis(expire));
    }

    /**
     * 解锁
     */
    public void unlock(String name) {
        delete(name);
    }
}
