package com.artfess.redis.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;

@Component
public class RedisLockUtils {
    private static final Logger log = LoggerFactory.getLogger(RedisLockUtils.class);
    private static final int DEFAULT_SINGLE_EXPIRE_TIME = 30;
    private static final int DEFAULT_BATCH_EXPIRE_TIME = 60;
    private RedisConnectionFactory redisConnectionFactory;
    private String prefix = "lock:";

    public RedisLockUtils(RedisConnectionFactory redisConnectionFactory) {
        this.redisConnectionFactory = redisConnectionFactory;
    }

    public boolean tryLock(String key) {
        return this.tryLock((String)key, 0L, (TimeUnit)null);
    }

    public boolean tryLock(String key, long timeout, TimeUnit unit) {
        RedisConnection connection = this.redisConnectionFactory.getConnection();
        String lockKey = this.prefix.concat(key);

        try {
            long nano = System.nanoTime();

            do {
                log.debug("try lock key: {}", lockKey);
                Boolean status = connection.setNX(lockKey.getBytes(), new byte[1]);
                if (status) {
                    connection.expire(lockKey.getBytes(), 30L);
                    log.debug("get lock, key: {} , expire in {} seconds.", lockKey, 30);
                    boolean var10 = Boolean.TRUE;
                    return var10;
                }

                log.debug("key: {} locked by another business：", lockKey);
                if (timeout <= 0L) {
                    break;
                }

                Thread.sleep(30L);
            } while(System.nanoTime() - nano < unit.toNanos(timeout));

            boolean var16 = Boolean.FALSE;
            return var16;
        } catch (Exception var14) {
            log.error(var14.getMessage(), var14);
        } finally {
            connection.close();
        }

        return Boolean.FALSE;
    }

    public void lock(String key) {
        RedisConnection connection = this.redisConnectionFactory.getConnection();
        String lockKey = this.prefix.concat(key);

        try {
            while(true) {
                log.debug("lock key: " + lockKey);
                Boolean status = connection.setNX(lockKey.getBytes(), lockKey.getBytes());
                if (status) {
                    connection.expire(lockKey.getBytes(), 30L);
                    log.debug("get lock, key: {} , expire in {} seconds.", lockKey, 30);
                    return;
                }

                log.debug("key: {} locked by another business：", lockKey);
                Thread.sleep(300L);
            }
        } catch (Exception var8) {
            log.error(var8.getMessage(), var8);
        } finally {
            connection.close();
        }

    }

    public void unLock(String key) {
        if (null == key) {
            key = "null";
        }

        List<String> list = new ArrayList(1);
        list.add(key);
        this.unLock((List)list);
    }

    public boolean tryLock(List<String> keyList) {
        return this.tryLock((List)keyList, 0L, (TimeUnit)null);
    }

    public boolean tryLock(List<String> keyList, long timeout, TimeUnit unit) {
        RedisConnection connnection = this.redisConnectionFactory.getConnection();

        try {
            List<String> needLocking = new CopyOnWriteArrayList();
            List<byte[]> locked = new CopyOnWriteArrayList();
            long nano = System.nanoTime();

            do {
                connnection.openPipeline();
                Iterator var10 = keyList.iterator();

                while(var10.hasNext()) {
                    String key = (String)var10.next();
                    String lockKey = this.prefix.concat(key);
                    needLocking.add(lockKey);
                    connnection.setNX(lockKey.getBytes(), lockKey.getBytes());
                }

                log.debug("try lock keys: " + needLocking);
                List<Object> results = connnection.closePipeline();

                for(int i = 0; i < results.size(); ++i) {
                    Boolean result = (Boolean)results.get(i);
                    String key = (String)needLocking.get(i);
                    if (result) {
                        connnection.expire(key.getBytes(), 60L);
                        locked.add(key.getBytes());
                    }
                }

                needLocking.removeAll(locked);
                if (needLocking.size() == 0) {
                    boolean var22 = true;
                    return var22;
                }

                log.debug("keys: {} locked by another business：", needLocking);
                if (timeout == 0L) {
                    break;
                }

                Thread.sleep(500L);
            } while(System.nanoTime() - nano < unit.toNanos(timeout));

            if (locked.size() > 0) {
                connnection.del((byte[][])locked.toArray(new byte[0][0]));
            }

            boolean var20 = false;
            return var20;
        } catch (Exception var17) {
            log.error(var17.getMessage(), var17);
            return true;
        } finally {
            connnection.close();
        }
    }

    public void unLock(List<String> keyList) {
        List<byte[]> keys = new CopyOnWriteArrayList();
        Iterator var4 = keyList.iterator();

        while(var4.hasNext()) {
            String key = (String)var4.next();
            String lockKey = this.prefix.concat(key);
            keys.add(lockKey.getBytes());
        }

        RedisConnection connection = this.redisConnectionFactory.getConnection();

        try {
            if (keys.size() > 0) {
                connection.del((byte[][])keys.toArray(new byte[0][]));
                log.debug("release lock, keys : {}", keys);
            }
        } catch (Exception var9) {
            log.error(var9.getMessage(), var9);
        } finally {
            connection.close();
        }

    }
}
