package com.ruoyi.common.auth.ali;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 支付宝认证服务
 * @author wjh
 * 2024/11/25
 */
@Service
@Slf4j
public class AliAuthService {

    @Autowired
    private AlipayClient defaultAlipayClient;

    @Autowired
    private AliConfig defaultAliConfig;


    public String getOpenId(String loginCode, AliConfig config) {
        AlipayClient alipayClient = config.alipayClient();

        // 构造请求参数以调用接口
        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        // 设置授权码
        request.setCode(loginCode);
        // 设置授权方式
        request.setGrantType("authorization_code");

        try {
            AlipaySystemOauthTokenResponse response = alipayClient.certificateExecute(request);
            System.out.println(response.getBody());
            ServiceUtil.assertion(!response.isSuccess(), response.getMsg());
            return response.getOpenId();
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 通过密文获取到手机号
     */
    public String getPhoneNumber(String ciphertext, AliConfig aliConfig) {
        if (StringUtils.isBlank(ciphertext) || aliConfig == null) {
            return null;
        }

        // 解密
        String str = this.decrypt(ciphertext, aliConfig.getAesPrivateKey(), aliConfig.getAlipayCertPath());

        // 转为json，获取手机号
        JSONObject json = JSON.parseObject(str);
        String code = json.getString("code");
        if ( StringUtils.isBlank(code) || !code.equals("10000")) {
            log.error("获取手机号失败：" + str);
            return null;
        }
        return json.getString("mobile");
    }


    private void checkSign(String content, String sign, String alipayCertPath) {
        //编码格式
        String charset="utf-8";
        //签名方式
        String sign_type="RSA2";
        //验签方法
        try {
            boolean signVerified= AlipaySignature.rsaCertCheck(content, sign, alipayCertPath, charset, sign_type);
            ServiceUtil.assertion(!signVerified, "验签未通过");
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 解密
     *
     * @param response       前端响应（密文）
     * @param aesPrivateKey AES秘钥
     * @param alipayCertPath 支付宝公钥证书路径
     */
    private String decrypt(String response, String aesPrivateKey, String alipayCertPath) {
        //1. 获取验签和解密所需要的参数
        Map<String, String> openapiResult = JSON.parseObject(response,new TypeReference<Map<String, String>>() {}, Feature.OrderedField);

        String charset = "UTF-8";
        String sign = openapiResult.get("sign");
        String content = openapiResult.get("response");
        //判断是否为加密内容
        boolean isDataEncrypted = !content.startsWith("{");

        //2. 验签
        String signContent = content;
        if (isDataEncrypted) {
            signContent = "\"" + signContent + "\"";
        }
        this.checkSign(signContent, sign, alipayCertPath);

        //3. 解密
        String encryptType = "AES";
        String plainData = null;
        if (isDataEncrypted) {
            try {
                plainData = AlipayEncrypt.decryptContent(content, encryptType, aesPrivateKey, charset);
            } catch (AlipayApiException e) {
                //解密异常, 记录日志
                throw new ServiceException("解密异常:" + e.getMessage());
            }
        } else {
            plainData = content;
        }

        return plainData;
    }

}
