package com.jeequan.jeepay.pay.ctrl.channel;

import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConstants;
import com.alipay.api.internal.util.AlipaySignature;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService;
import com.jeequan.jeepay.core.interfaces.paychannel.IMchAutoAuthService;
import com.jeequan.jeepay.core.model.DBApplicationConfig;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig;
import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.MchAppEntity;
import com.jeequan.jeepay.db.entity.PayInterfaceConfig;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.PayInterfaceConfigService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;
import java.io.PrintWriter;

/**
* 渠道侧自定义业务ctrl
*
* @author terrfly
*
* @date 2021/7/15 11:49
*/
@Slf4j
@Controller
@RequestMapping("/api/channelbiz/alipay")
public class AlipayBizController extends AbstractCtrl {

    @Autowired private IConfigContextQueryService configContextQueryService;
    @Autowired private SysConfigService sysConfigService;
    @Autowired private PayInterfaceConfigService payInterfaceConfigService;
    @Autowired private MchAppService mchAppService;
    @Autowired private IMQSender mqSender;

    /** 跳转到支付宝的授权页面 （统一从pay项目获取到isv配置信息）
     * isvAndMchNo 格式:  ISVNO_MCHAPPID
     * example: https://pay.jeepay.cn/api/channelbiz/alipay/redirectAppToAppAuth/V1623998765_60cc41694ee0e6685f57eb1f
     * **/
    @RequestMapping("/redirectAppToAppAuth/{isvAndMchAppId}")
    public void redirectAppToAppAuth(@PathVariable("isvAndMchAppId") String isvAndMchAppId) throws IOException {

        String isvNo = isvAndMchAppId.split("_")[0];

        AlipayIsvParams alipayIsvParams = (AlipayIsvParams) configContextQueryService.queryIsvParams(isvNo, CS.IF_CODE.ALIPAY);
        alipayIsvParams.getSandbox();

        String oauthUrl = AlipayConfig.PROD_APP_TO_APP_AUTH_URL;
        if(alipayIsvParams.getSandbox() != null && alipayIsvParams.getSandbox() == CS.YES){
            oauthUrl = AlipayConfig.SANDBOX_APP_TO_APP_AUTH_URL;
        }

        String redirectUrl = sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/channelbiz/alipay/appToAppAuthCallback";
        response.sendRedirect(String.format(oauthUrl, alipayIsvParams.getAppId(), URLUtil.encodeAll(redirectUrl), isvAndMchAppId));
    }

    /** 支付宝授权回调地址 **/
    @RequestMapping("/appToAppAuthCallback")
    public String appToAppAuthCallback() {

        String errMsg = null;
        boolean isAlipaySysAuth = true; //是否 服务商登录支付宝后台系统发起的商户授权， 此时无法获取authCode和商户的信息。

        try {
            // isvAndMchAppId 格式:  ISVNO_MCHAPPID,  如果isvAndMchNo为空说明是： 支付宝后台的二维码授权之后的跳转链接。
            String isvAndMchAppId = getValString("state");
            String appAuthCode = getValString("app_auth_code"); // 支付宝授权code

            if(StringUtils.isNotEmpty(isvAndMchAppId) && StringUtils.isNotEmpty(appAuthCode)){
                isAlipaySysAuth = false;
                String isvNo = isvAndMchAppId.split("_")[0];
                String mchAppId = isvAndMchAppId.split("_")[1];

                MchAppEntity mchAppEntity = mchAppService.getById(mchAppId);

                MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(mchAppEntity.getMchNo(), mchAppId);

                IMchAutoAuthService mchAutoAuthService = SpringBeansUtil.getBean(CS.IF_CODE.ALIPAY + "MchAutoAuthService", IMchAutoAuthService.class);

                JSONObject result = mchAutoAuthService.mchAuth(mchAppConfigContext, appAuthCode);

                String appAuthToken = result.getString("appAuthToken");
                JSONObject ifParams = new JSONObject();
                ifParams.put("appAuthToken", appAuthToken); ifParams.put("refreshToken", result.getString("appRefreshToken")); ifParams.put("expireTimestamp", result.getString("expiresIn"));

                PayInterfaceConfig dbRecord = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.MCH_APP, mchAppId, CS.IF_CODE.ALIPAY);

                if(dbRecord != null){
                    PayInterfaceConfig updateRecord = new PayInterfaceConfig();
                    updateRecord.setId(dbRecord.getId()); updateRecord.setIfParams(ifParams.toJSONString());
                    payInterfaceConfigService.updateById(updateRecord);
                }else{

                    dbRecord = new PayInterfaceConfig();
                    dbRecord.setInfoType(CS.SYS_ROLE_TYPE.MCH_APP);
                    dbRecord.setInfoId(mchAppId);
                    dbRecord.setIfCode(CS.IF_CODE.ALIPAY);
                    dbRecord.setIfParams(ifParams.toJSONString());
                    dbRecord.setState(CS.YES);
                    dbRecord.setCreatedBy("SYS");
                    dbRecord.setCreatedUid(0L);
                    payInterfaceConfigService.save(dbRecord);
                }

            }
        } catch (Exception e) {
            log.error("error", e);
            errMsg = StringUtils.defaultIfBlank(e.getMessage(), "系统异常！");
        }

        request.setAttribute("errMsg", errMsg);
        request.setAttribute("isAlipaySysAuth", isAlipaySysAuth);
        // 静态CDN地址
        DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
        request.setAttribute("staticCdnHost", dbApplicationConfig.getStaticCdnHost());

        return "channel/alipay/isvsubMchAuth";
    }





    /**
     *  支付宝公共方法 加密函数。
     * **/
    private static String encryptAndSign(String bizContent, String alipayPublicKey, String cusPrivateKey, String charset,
                                        boolean isEncrypt, boolean isSign, String signType) throws AlipayApiException {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isEmpty(charset)) {
            charset = AlipayConstants.CHARSET_GBK;
        }
        sb.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>");
        if (isEncrypt) {// 加密
            sb.append("<alipay>");
            String encrypted = AlipaySignature.rsaEncrypt(bizContent, alipayPublicKey, charset);
            sb.append("<response>" + encrypted + "</response>");
            sb.append("<encryption_type>AES</encryption_type>");
            if (isSign) {
                String sign = AlipaySignature.rsaSign(encrypted, cusPrivateKey, charset, signType);
                sb.append("<sign>" + sign + "</sign>");
                sb.append("<sign_type>");
                sb.append(signType);
                sb.append("</sign_type>");
            }
            sb.append("</alipay>");
        } else if (isSign) {// 不加密，但需要签名
            sb.append("<alipay>");
            sb.append("<response>" + bizContent + "</response>");
            String sign = AlipaySignature.rsaSign(bizContent, cusPrivateKey, charset, signType);
            sb.append("<sign>" + sign + "</sign>");
            sb.append("<sign_type>");
            sb.append(signType);
            sb.append("</sign_type>");
            sb.append("</alipay>");
        } else {// 不加密，不加签
            sb.append(bizContent);
        }
        return sb.toString();
    }


    /**
     * 接收  支付宝 应用 配置中： 【应用网关地址 ： 用于接收支付宝沙箱异步通知消息（例如 From蚂蚁消息等），需要传入http(s)公网可访问的网页地址。选填，若不设置，则无法接收相应的异步通知消息。】
     *
     * **/
    @RequestMapping("/appGatewayMsgReceive")
    public ModelAndView alipayAppGatewayMsgReceive() {

        JSONObject reqJSON = getReqParamJSON();

        // 获取到报文信息， 然后 转发到对应的ctrl
        log.error("支付宝应用网关接收消息参数：{}", reqJSON);

//        // 分账交易通知
//        if("alipay.trade.order.settle.notify123123".equals(reqJSON.getString("msg_method"))){
//
//            // 直接转发到 分账通知的 URL去。
//            ModelAndView mv = new ModelAndView();
//            mv.setViewName("forward:/api/divisionRecordChannelNotify/" + CS.IF_CODE.ALIPAY);
//            return mv;
//        }


        // 测试。
        if(true){

            AlipayIsvParams isvParams = (AlipayIsvParams)configContextQueryService.queryIsvParams("V1648865874", CS.IF_CODE.ALIPAY);

            String publicKey = isvParams.getAlipayPublicKey();
            String PRIVATE_KEY = isvParams.getPrivateKey();

            //支付宝响应消息
            String bizContent = "<success>true</success>";

            try {
                //对响应内容加签
                String responseMsg = encryptAndSign(bizContent, publicKey, PRIVATE_KEY, "UTF-8", false, true, "RSA2");

                log.error("响应支付宝：{}", responseMsg);

                //http 内容应答
                response.reset();
                response.setContentType("text/xml;charset=GBK");
                PrintWriter printWriter = response.getWriter();
                printWriter.print(responseMsg);
                response.flushBuffer();

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


        throw new BizException("无此事件["+ reqJSON.getString("msg_method") +"]处理器");

    }








}
