package com.bizzan.bitrade.service;

import java.util.Date;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

@Component
public class RedisLock {
	@Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Resource(name = "redisTemplate")
    private ValueOperations<Object,Object> valOps;

    @Resource(name = "redisTemplate")
    private SetOperations<Object,Object> setOps;

    /**
     * @Title:
     * @Description:   保存K-V,并设置时间
     * @return
     * @throws
     * @author qiaomengnan
     * @date 2019/06/28 01:51:32
     */
    public void save(Object key, Object value, long time){
        valOps.set(key,value,time,TimeUnit.SECONDS);
    }

    /**
     * @Title:
     * @Description:   获取过期时间
     * @param key
     * @return
     * @throws
     * @author qiaomengnan
     * @date 2019/11/01 10:22:46
     */
    public Long getExpire(Object key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * @Title:
     * @Description:   保存K-V,并设置时间
     * @return
     * @throws
     * @author qiaomengnan
     * @date 2019/06/28 01:51:32
     */
    public Object get(Object key){
        return valOps.get(key);
    }

    /**
     * @Title:
     * @Description:   保存K-V
     * @return
     * @throws
     * @author qiaomengnan
     * @date 2019/06/28 01:51:32
     */
    public void saveSetValue(Object key , Object ...value) {
        setOps.add(key, value);
    }

    /**
     * @Title:
     * @Description:   保存K-V
     * @return
     * @throws
     * @author qiaomengnan
     * @date 2019/06/28 01:51:32
     */
    public void saveSetValue(Object key , long time , Object ...value) {
        setOps.add(key, value,time,TimeUnit.SECONDS);
    }

    /**
     * @Title:
     * @Description:   判断一个key是否存在
     * @param key
     * @return
     * @throws
     * @author qiaomengnan
     * @date 2019/08/10 03:11:41
     */
    public boolean hasKey(Object key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * @Title:
     * @Description:   删除key
     * @param key
     * @return
     * @throws
     * @author qiaomengnan
     * @date 2019/09/04 09:30:18
     */
    public void delete(Object key) {
        redisTemplate.delete(key);
    }

    /**
     * @Title:
     * @Description:   获取Long类型的值
     * @param key 键
     * @return
     * @throws
     * @author qiaomengnan
     * @date 2019/08/07 04:47:58
     */
    public Long getLong(Object key) {
        try {
            Object res = valOps.get(key);
            return res == null ? null : Long.parseLong(res.toString());
        }catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }
    
    private boolean setNX(final String key, final String value) {
        return redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    public boolean lockBySeconds(String key, int seconds){
    	Long nowTime = new Date().getTime();
        Long exprirationTime = nowTime + (seconds * 1000);
        // 通过setNx获取锁
        boolean absent = setNX(key, String.valueOf(exprirationTime));
        if(!absent) {
        	Long absentExprirationTime = getLong(key);
        	if(absentExprirationTime == null || absentExprirationTime<nowTime) {
        		redisTemplate.delete(key);
        		return setNX(key, String.valueOf(exprirationTime));
        	}
        }
        return absent;
    }
    
    public void unlock(String key) {
    	redisTemplate.delete(key);
    }
    
    public boolean lockWalletForClose(Long walletId) {
    	String key = "WALLET_LOCK_FOR_CLOSE:" + walletId;
    	return this.lockBySeconds(key, 2);
    }
    
    public void unlockWalletForClose(Long walletId) {
    	String key = "WALLET_LOCK_FOR_CLOSE:" + walletId;
    	this.unlock(key);
    }
    
    public boolean lockOrder(Long orderId) {
    	String key = "ORDER_LOCK:" + orderId;
    	return this.lockBySeconds(key, 2);
    }
    
    public void unlockOrder(Long orderId) {
    	String key = "ORDER_LOCK:" + orderId;
    	this.unlock(key);
    }

}
