package org.onetwo.boot.module.oauth2.token;

import java.util.concurrent.TimeUnit;

import org.onetwo.boot.core.jwt.JwtErrors;
import org.onetwo.boot.module.redis.JsonValueRedisTemplate;
import org.onetwo.common.exception.ServiceException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.util.Assert;

/**
 * @author wayshall
 * <br/>
 */
public class JwtTokenRedisStore extends JwtTokenStore implements InitializingBean {

	public static final String OAUTH_JWT_TOKEN_PREFIX = "oauth2:jwt:";
	public static final String OAUTH_TOKEN_ID_PREFIX = "jf.";
	
	@Autowired
	private RedisConnectionFactory connectionFactory;
	private JsonValueRedisTemplate<JwtStoredTokenValue> redisTemplate;

	public JwtTokenRedisStore(JwtAccessTokenConverter jwtTokenEnhancer) {
		super(jwtTokenEnhancer);
	}
	

	@Override
	public void afterPropertiesSet() throws Exception {
		this.redisTemplate = new JsonValueRedisTemplate<JwtStoredTokenValue>(connectionFactory, JwtStoredTokenValue.class);
//		Assert.notNull(redisTemplate, "redisTemplate can not be null");
	}


	@Override
	public OAuth2Authentication readAuthentication(String token) {
//		JwtStoredTokenValue storedTokenValue = getJwtStoredTokenValue(tokenId);
		return super.readAuthentication(token);
	}
	
	/***
	 * 
	 */
	/*@Override
	public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
		String key = getStoreKey(token.getValue());
		BoundValueOperations<String, JwtStoredTokenValue> ops = redisTemplate.boundValueOps(key);
		JwtStoredTokenValue storedTokenValue = ops.get();
		return readAuthentication(storedTokenValue.getToken());
	}*/
	
	/***
	 * resouce server auth token
	 */
	@Override
	public OAuth2AccessToken readAccessToken(String tokenId) {
		JwtStoredTokenValue storedTokenValue = getJwtStoredTokenValue(tokenId);
		OAuth2AccessToken accessToken = super.readAccessToken(storedTokenValue.getToken());
		return accessToken;
	}

	/***
	 * auth server store accessToken
	 * tokenEndpoint store acessToken
	 */
	@Override
	public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
		DefaultOAuth2AccessToken at = (DefaultOAuth2AccessToken) token;
		String tokenId = getTokenId(at);
		Assert.hasLength(tokenId, "tokenId can not be null");
		String key = getStoreKey(tokenId);
		JwtStoredTokenValue value = JwtStoredTokenValue.builder()
											.token(at.getValue())
											.build();
		BoundValueOperations<String, JwtStoredTokenValue> ops = redisTemplate.boundValueOps(key);
		//保存到redis并设置过期时间
		ops.set(value, at.getExpiresIn(), TimeUnit.MILLISECONDS);
		//把tokenvalue置换为tokenId
		at.setValue(tokenId);
	}
	
	protected String getTokenId(DefaultOAuth2AccessToken at){
		String tokenId = OAUTH_TOKEN_ID_PREFIX+(String)at.getAdditionalInformation().get(JwtAccessTokenConverter.TOKEN_ID);
		return tokenId;
	}
	
	protected final JwtStoredTokenValue getJwtStoredTokenValue(String tokenId){
		String key = getStoreKey(tokenId);
		BoundValueOperations<String, JwtStoredTokenValue> ops = redisTemplate.boundValueOps(key);
		JwtStoredTokenValue storedTokenValue = ops.get();
		if(storedTokenValue==null){
			throw new ServiceException(JwtErrors.CM_ERROR_TOKEN);
		}
		return storedTokenValue;
	}
	

	@Override
	public void removeAccessToken(OAuth2AccessToken token) {
		super.removeAccessToken(token);
		String tokenId = token.getValue();
		String key = getStoreKey(tokenId);
		redisTemplate.delete(key);
	}
	
	private String getStoreKey(String key){
		return OAUTH_JWT_TOKEN_PREFIX + key;
	}
	
}

@@ -926,16 +926,54 @@
 t;%0A%0A/**%0A
+ * %E5%9F%BA%E4%BA%8Ejwt%EF%BC%8C%E6%8A%8Atokenid%E5%92%8Cjwt token%E6%98%A0%E5%B0%84%E4%BF%9D%E5%AD%98%E5%88%B0redis%0A
  * @auth
@@ -3338,30 +3338,30 @@
  at)%7B%0A%09%09
-String
+Object
  tokenId
  = OAUTH
@@ -3356,41 +3356,16 @@
 enId
- = OAUTH_TOKEN_ID_PREFIX+(String)
+Value = 
 at.g
@@ -3429,16 +3429,197 @@
 EN_ID);%0A
+%09%09if(tokenIdValue==null)%7B%0A%09%09%09throw new ServiceException(JwtErrors.CM_ERROR_TOKEN).put(%22token%22, at.getValue());%0A%09%09%7D%0A%09%09String tokenId = OAUTH_TOKEN_ID_PREFIX+tokenIdValue.toString();%0A
 %09%09return

add commnet and fix code