package com.fdkankan.common.constant;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String UNLOCK_LUA = "if redis.call('get',KEYS[1]) == ARGV[1] then\n" +
                                "    return redis.call('del',KEYS[1])\n" +
                                "else\n" +
                                "    return 0\n" +
                                "end";

    /**
     * 加锁，自旋重试三次
     *
     * @param lockKey 锁key
     * @param expireTime 锁过期时间 单位 毫秒
     * @return
     */
    public boolean lock(String lockKey, int expireTime) {
        boolean locked = false;
        int tryCount = 3;
        long threadId = Thread.currentThread().getId();
        while (!locked && tryCount > 0) {
            locked = redisTemplate.opsForValue().setIfAbsent(lockKey, threadId, expireTime, TimeUnit.MILLISECONDS);
            tryCount--;
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                log.error("线程被中断[线程id:" + threadId + "]", e);
            }
        }
        return locked;
    }

    /**
     * 非原子解锁，可能解别人锁，不安全
     *
     * @param redisLockEntity
     * @return
     */
    public boolean unlock(String lockKey, Long threadId) {
        if (StrUtil.isEmpty(lockKey) || Objects.isNull(threadId))
            return false;
        boolean releaseLock = false;
        Long val = (Long) redisTemplate.opsForValue().get(lockKey);
        if (threadId.equals(val)) {
            releaseLock = redisTemplate.delete(lockKey);
        }
        return releaseLock;
    }

    /**
     * 使用lua脚本解锁，不会解除别人锁
     *
     * @param
     * @return
     */
    public boolean unlockLua(String lockKey, Long threadId) {
        if (StrUtil.isEmpty(lockKey) || Objects.isNull(threadId))
            return false;
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript();
//        redisScript.setLocation(new ClassPathResource("unlock.lua"));
        redisScript.setScriptText(UNLOCK_LUA);
        redisScript.setResultType(Long.class);

        Object result = redisTemplate.execute(redisScript, Arrays.asList(lockKey), threadId);
        return result.equals(Long.valueOf(1));
    }





}
