package com.wish.pay.ali;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayRequest;
import com.alipay.api.AlipayResponse;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.internal.util.StringUtils;
import com.beust.jcommander.internal.Lists;
import com.beust.jcommander.internal.Maps;
import com.wish.pay.ali.common.AliPayConstants;
import com.wish.pay.common.model.result.PayResult;
import com.wish.pay.common.utils.Base64;
import org.apache.http.HttpServerConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

import static org.apache.commons.codec.CharEncoding.UTF_8;

/**
 * @author fqh
 * @email [email protected]
 * @date 2017/3/1 17:10
 */
public class AliPayUtil {

    static Logger log = LoggerFactory.getLogger(AliPayUtil.class);


    // 调用AlipayClient的execute方法,进行远程调用
    @SuppressWarnings({"rawtypes", "unchecked"})
    protected static AlipayResponse getResponse(AlipayClient client, AlipayRequest request) {
        try {
            AlipayResponse response = client.execute(request);
            if (response != null) {
                log.info(response.getBody());
            }
            return response;

        } catch (AlipayApiException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取阿里支付链接的所有参数列表
     *
     * @param request
     * @return
     */
    public static Map<String, String> getAlipayNotify(HttpServletRequest request) {
        Map<String, String> params = Maps.newHashMap();
        Map requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }
        return params;
    }


    /**
     * 把数组所有元素按照字母顺序排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * <p>
     * 第一步: 在通知返回参数列表中,除去sign、sign_type两个参数外,凡是通知返回回来的参数皆是待验签的参数。
     * 第二步:将剩下参数进行url_decode, 然后进行字典排序,组成字符串,得到待签名字符串
     *
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     * @Link 异步返回结果的验签:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.OSyDs4&treeId=194&articleId=103296&docType=1#s1
     */
    public static String createStringUrl(Map<String, String> params) {

        List<String> keys = Lists.newArrayList(params.keySet());
        Collections.sort(keys);

        StringBuffer prestr = new StringBuffer();

        int keySize = keys.size();
        int lastKeyLength = keySize - 1;
        for (int i = 0; i < keySize; i++) {
            String key = keys.get(i);
           /* if (*//*key.equals("sign") ||*//* key.equals("sign_type")) {//除去sign、sign_type两个参数
                continue;
            }*/

            String value = params.get(key);
            if (i == lastKeyLength) {//拼接时,不包括最后一个&字符
                prestr.append(key).append("=").append(value);
            } else {
                prestr.append(key).append("=").append(value).append("&");
            }
        }

        return prestr.toString();
    }

    /**
     * RSA验签名检查
     * 第三步: 将签名参数(sign)使用base64解码为字节码串。
     * 第四步 使用RSA的验签方法,通过签名字符串、签名参数(经过base64解码)及支付宝公钥验证签名。
     *
     * @param content        待签名数据
     * @param sign           签名值
     * @param ali_public_key 支付宝公钥
     * @param input_charset  编码格式
     * @return 布尔值
     * @Link 异步返回结果的验签:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.OSyDs4&treeId=194&articleId=103296&docType=1#s1
     */
    public static boolean verify(String content, String sign, String ali_public_key, String input_charset) {
        try {
            /*PublicKey e = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
            Signature signature = Signature.getInstance("SHA256WithRSA");
            signature.initVerify(e);
            if(StringUtils.isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }

            return signature.verify(com.alipay.api.internal.util.codec.Base64.decodeBase64(sign.getBytes()));*/
            KeyFactory keyFactory = KeyFactory.getInstance(AliPayConstants.ALIPAY_SIGN_TYPE);
            byte[] encodedKey = Base64.decode(ali_public_key);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

            java.security.Signature signature = java.security.Signature.getInstance(AliPayConstants.SIGN_ALGORITHMS);

            signature.initVerify(pubKey);
            signature.update(content.getBytes(input_charset));

            boolean bverify = signature.verify(Base64.decode(sign));
            return bverify;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 返回验签结果
     *
     * @param params
     * @param aliPublicKey
     * @return
     */
    public static boolean verifySignWithRSA(Map<String, String> params, String aliPublicKey) {
       /* String content = createStringUrl(params);
        String sign = params.get("sign");*/
        String sign_type = params.get("sign_type");
        try {
            return  AlipaySignature.rsaCheckV1(params, aliPublicKey, "UTF-8", sign_type);
            //return AlipaySignature.rsaCheckV2(params, aliPublicKey, UTF_8);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return false;
        }
        //String sign_type = params.get("sign_type");
       /* try {
            AlipaySignature.rsaSign(content,aliPublicKey,"UTF-8",sign_type);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return verify(content, sign, aliPublicKey, "UTF-8");*/
    }

}