package jnpf.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Component
public class RedisDistributedLock {

    private final RedisTemplate<String, String> redisTemplate;

    // Lua脚本用于原子性解锁
    private static final String UNLOCK_SCRIPT =
            "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                    "   return redis.call('del', KEYS[1]) " +
                    "else " +
                    "   return 0 " +
                    "end";

    @Autowired
    public RedisDistributedLock(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 尝试获取分布式锁
     * @param lockKey 锁的key
     * @param requestId 请求标识（建议使用UUID）
     * @param expireTime 锁的过期时间（毫秒）
     * @return 是否获取成功
     */
    public boolean tryLock(String lockKey, String requestId, long expireTime) {
        return Boolean.TRUE.equals(
                redisTemplate.opsForValue().setIfAbsent(
                        lockKey,
                        requestId,
                        expireTime,
                        TimeUnit.MILLISECONDS
                )
        );
    }

    /**
     * 释放分布式锁
     * @param lockKey 锁的key
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public boolean releaseLock(String lockKey, String requestId) {
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class);
        Long result = redisTemplate.execute(
                redisScript,
                Collections.singletonList(lockKey),
                requestId
        );
        return result != null && result == 1;
    }

    /**
     * 获取锁的简单方法（自动生成requestId）
     * @param lockKey 锁的key
     * @param expireTime 锁的过期时间（毫秒）
     * @return requestId 如果获取成功，否则null
     */
    public String lock(String lockKey, long expireTime) {
        String requestId = UUID.randomUUID().toString();
        if (tryLock(lockKey, requestId, expireTime)) {
            return requestId;
        }
        return null;
    }
}