package com.hai.config;

import com.alibaba.fastjson.JSONObject;
import com.hai.common.pay.util.sdk.WXPayConstants;
import com.hai.common.utils.RedisUtil;
import com.hai.common.utils.UnionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.xml.bind.DatatypeConverter;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.*;

/**
 * 银联用户信息
 * @author hurui
 */
@Component
public class UnionUserConfig {

    private static String requestUrl = "https://open.95516.com/open/access/1.0/";
    private static String appId =  CommonSysConst.getSysConfig().getUnionAppId();
    private static String secret = CommonSysConst.getSysConfig().getUnionSecret();
    private static String rsaKey = CommonSysConst.getSysConfig().getUnionRsaKey();

    @Resource
    private RedisUtil redisUtil;

    /**
     * 获取应用访问令牌backendToken
     * @return
     */
    public String getBackendToken() {
        Object token = redisUtil.get("UNION_BACKEND_TOKEN");
        if (token != null) {
            return token.toString();
        }
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("appId", appId);
        paramMap.put("secret", secret);
        paramMap.put("nonceStr", UnionUtils.createNonceStr());
        paramMap.put("timestamp", String.valueOf(System.currentTimeMillis()/1000));
        paramMap.put("signature", generateSign(paramMap));
        paramMap.remove("secret");
        JSONObject jsonObject = JSONObject.parseObject(UnionUtils.sendPostGson(requestUrl+"backendToken", paramMap));
        String backendToken = jsonObject.getJSONObject("params").getString("backendToken");
        redisUtil.set("UNION_BACKEND_TOKEN", backendToken,jsonObject.getJSONObject("params").getLong("expiresIn"));
        return backendToken;
    }

    /**
     * 获取授权访问令牌accessToken
     * @return
     */
    public JSONObject getAccessToken(String backendToken,String code) {
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("appId", appId);
        paramMap.put("secret", secret);
        paramMap.put("nonceStr", UnionUtils.createNonceStr());
        paramMap.put("timestamp", String.valueOf(System.currentTimeMillis()/1000));

        paramMap.put("backendToken", backendToken);
        paramMap.put("code", code);
        paramMap.put("grantType", "authorization_code");
        paramMap.put("signature", generateSign(paramMap));
        paramMap.remove("secret");
        return JSONObject.parseObject(UnionUtils.sendPostGson(requestUrl+"token", paramMap));
    }


    /**
     * 获取用户手机号
     * @return
     */
    public JSONObject getUserMobile(String backendToken,String accessToken,String openId) {
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("appId", appId);
        paramMap.put("secret", secret);
        paramMap.put("nonceStr", UnionUtils.createNonceStr());
        paramMap.put("timestamp", String.valueOf(System.currentTimeMillis()/1000));

        paramMap.put("backendToken", backendToken);
        paramMap.put("accessToken", accessToken);
        paramMap.put("openId", openId);
        paramMap.put("signature", generateSign(paramMap));
        paramMap.remove("secret");
        return JSONObject.parseObject(UnionUtils.sendPostGson(requestUrl+"user.mobile", paramMap));
    }


    /**
     * 参数排序
     * @param param
     * @return
     */
    private static String paramSort(final Map<String, String> param) {
        Set<String> keySet = param.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals(WXPayConstants.FIELD_SIGN)) {
                continue;
            }
            if (StringUtils.isBlank(sb.toString())) {
                sb.append(k).append("=").append(param.get(k));
            } else {
                sb.append("&").append(k).append("=").append(param.get(k));
            }
        }
        return sb.toString();
    }

    /**
     * 生成签名
     * @param data
     * @return
     * @throws Exception
     */
    private static String generateSign(Map<String, String> data){
        data.put("secret", secret);
        String sign = sha256(paramSort(data).getBytes());
        return sign;
    }

    /**
     * 生成随机16位随机字符串
     * @return
     */
    public static String createNonceStr(){
        String sl = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder sb = new StringBuilder();
        for(int i = 0 ; i < 16 ; i ++){
            sb.append(sl.charAt(new Random().nextInt(sl.length())));
        }
        return sb.toString();
    }

    public String getRsaKey(){
        return rsaKey;
    }

    public static String sha256(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            return bytesToHex(md.digest(data));
        } catch (Exception ex) {
            return null;
        }
    }

    public static String bytesToHex(byte[] bytes) {
        String hexArray = "0123456789abcdef";
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            int bi = b & 0xff;
            sb.append(hexArray.charAt(bi >> 4));
            sb.append(hexArray.charAt(bi & 0xf));
        }
        return sb.toString();
    }

    public static Map<String, Object> generatorRSA(){
        KeyPairGenerator keyGen = null;
        try {
            keyGen = KeyPairGenerator.getInstance("RSA");
            keyGen.initialize(1024);
            KeyPair keyPair = keyGen.generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

            String publicKeyBase64 = DatatypeConverter.printBase64Binary(publicKey.getEncoded());
            String privateKeyBase64 = DatatypeConverter.printBase64Binary(privateKey.getEncoded());

            Map<String, Object> map = new HashMap<>();
            map.put("publicKey", publicKeyBase64);
            map.put("privateKey", privateKeyBase64);
            return map;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
}
