package com.css.simulation.resource.scheduler.infra.db.redis;

import api.common.util.CollectionUtil;
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.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Slf4j
public class CustomRedisClient {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public  Set<String> getKeySetByPrefixAndContent(StringRedisTemplate stringRedisTemplate, String prefix,String content) {
        final Set<String> keys = stringRedisTemplate.keys(prefix + "*");
        if (CollectionUtil.isNotEmpty(keys)) {
            return keys.stream().filter(key -> key.contains(content)).collect(Collectors.toSet());
        } else {
            return new HashSet<>();
        }
    }

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

    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  void increment(String key, long number) {
        stringRedisTemplate.opsForValue().increment(key, number);
    }

    /**
     * 减值
     */
    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, "任意值", Duration.ofMillis(expire));
    }

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