package com.cftech.core.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cftech.accounts.model.MpAccountsEntity;
import com.cftech.accounts.service.MpAccountsService;
import com.cftech.core.constants.WxApiConstants;
import com.cftech.qy.api.WebHttpInterface;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.concurrent.TimeUnit;

/**
 * 企业号 ACCESS TOKEN 管理
 * @author Neil
 *
 */
@Slf4j
@Component
public class QyTokenUtil {

	@Autowired
	private MpAccountsService accountService;
	@Autowired
	private RedisTemplate<String, String> redisTemplate;

//	@Autowired
//	private WebHttpInterface webHttpInterface;
	
	private RedisTemplate<String, String> getConfig() {
		StringRedisSerializer stringSerializer = new StringRedisSerializer();
		redisTemplate.setKeySerializer(stringSerializer);
		//redisTemplate.setValueSerializer(stringSerializer);
		redisTemplate.setHashKeySerializer(stringSerializer);
		redisTemplate.setHashValueSerializer(stringSerializer);
		return redisTemplate;
	}
	/**
	 * 
	 * 通过企业号corpid刷新最新的token，并返回
	 * @return
	 */
	public String getToken(Long accountId)//更新token
	{
		MpAccountsEntity accountsEntity = searchAccountsById(accountId);
		if (accountsEntity == null) {
			return null;
		}
		// accesstoken的key
		String key = "CORPID_" + accountsEntity.getAgentId() + "_" + accountsEntity.getAppid();
		// jstoken的key
		String jskey = "CORPIDJS_" + accountsEntity.getAgentId() + "_" +accountsEntity.getAppid();
		if (getConfig().hasKey(key)) {
			return getConfig().opsForValue().get(key);
		}
		// 请求企业号认证信息
		String token = null;// 缓存token至redis
		try {
			String url = WxApiConstants.TOKEN_GET.replace("CORPID", accountsEntity.getAppid())
                            .replace("SECRECT", accountsEntity.getSecret());
			String retStr = OKHttpUtils.getJSON(url);
			JSONObject retObj = JSON.parseObject(retStr);
			token = retObj.getString("access_token");


			getConfig().opsForValue().set(key, token);
			getConfig().expire(key, 6000, TimeUnit.SECONDS);

			// 继续缓存jsticket
			url = WxApiConstants.JSAPI_TICKET_GET.replace("ACCESS_TOKEN", token);
			retStr = OKHttpUtils.getJSON(url);
			retObj = JSON.parseObject(retStr);
			String jsTicket = retObj.getString("ticket");

			// 缓存token至redis
			getConfig().opsForValue().set(jskey, jsTicket);
			getConfig().expire(jskey, 6000, TimeUnit.SECONDS);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return token;
	}

	public String getToken(MpAccountsEntity accountsEntity)//更新token
	{
		if (accountsEntity == null) {
			return null;
		}
		// accesstoken的key
		String key = "CORPID_" + accountsEntity.getAgentId() + "_" +  accountsEntity.getAppid();
		// jstoken的key
		String jskey = "CORPIDJS_" + accountsEntity.getAgentId() + "_" +  accountsEntity.getAppid();
		if (getConfig().hasKey(key)) {
			return getConfig().opsForValue().get(key);
		}
		// 请求企业号认证信息
		String url = WxApiConstants.TOKEN_GET.replace("CORPID", accountsEntity.getAppid())
				.replace("SECRECT", accountsEntity.getSecret());
		try {
			String retStr = OKHttpUtils.getJSON(url);
			JSONObject retObj = JSON.parseObject(retStr);
			String token = retObj.getString("access_token");// 缓存token至redis
			getConfig().opsForValue().set(key, token);
			getConfig().expire(key, 6000, TimeUnit.SECONDS);

			// 继续缓存jsticket
			url = WxApiConstants.JSAPI_TICKET_GET.replace("ACCESS_TOKEN", token);
			retStr = OKHttpUtils.getJSON(url);
			retObj = JSON.parseObject(retStr);
			String jsTicket = retObj.getString("ticket");

			// 缓存token至redis
			getConfig().opsForValue().set(jskey, jsTicket);
			getConfig().expire(jskey, 6000, TimeUnit.SECONDS);

			return token;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	public String getJSTicket(Long accountId) {
		MpAccountsEntity accountsEntity = searchAccountsById(accountId);
		// jstoken的key
		String jskey = "CORPIDJS_" +  accountsEntity.getAgentId() + "_" + accountsEntity.getAppid();
		return getConfig().opsForValue().get(jskey);
	}

	public String getJSTicket(MpAccountsEntity accountsEntity) {
		// jstoken的key
		String jskey = "CORPIDJS_" + accountsEntity.getAgentId() + "_" + accountsEntity.getAppid();
		return getConfig().opsForValue().get(jskey);
	}

		/**
	 * 通过主键ID，获取公众号实体
	 */
	public MpAccountsEntity searchAccountsById(Long id){
		MpAccountsEntity accountsEntity = accountService.getDetail(id);
		return accountsEntity;
	} 
	
	/**
	 * 通过appid,获取公众号实体
	 */
	public MpAccountsEntity searchAccounts(String appid){
		MpAccountsEntity accountsEntity = accountService.getMpAccountsAppid(appid);
		return accountsEntity;
	}

	/**
	 * 做SHA-1签名
	 *
	 * @param jsapiTicket
	 * @param noncestr
	 * @param timestamp
	 * @param url
	 * @return
	 */
	public static String sign(String jsapiTicket, String noncestr, String timestamp, String url) {
		StringBuffer sb = new StringBuffer();
		sb.append("jsapi_ticket=");
		sb.append(jsapiTicket);
		sb.append("&");
		sb.append("noncestr=");
		sb.append(noncestr);
		sb.append("&");
		sb.append("timestamp=");
		sb.append(timestamp);
		sb.append("&");
		sb.append("url=");
		sb.append(url);
		try {
			MessageDigest crypt = MessageDigest.getInstance("SHA-1");
			crypt.reset();
			crypt.update(sb.toString().getBytes("UTF-8"));
			return byteToHex(crypt.digest());
		} catch (NoSuchAlgorithmException e) {
			log.error("QyTokenUtil sign error: {}", e.getMessage());
			return "";
		} catch (UnsupportedEncodingException e) {
			log.error("QyTokenUtil sign error: {}", e.getMessage());
			return "";
		}
	}

	private static String byteToHex(final byte[] hash) {
		Formatter formatter = new Formatter();
		for (byte b : hash) {
			formatter.format("%02x", b);
		}
		String result = formatter.toString();
		formatter.close();
		return result;
	}
}
