package com.jeequan.jeepay.thirdparty.channel.yspay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.exception.ResponseException;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService;
import com.jeequan.jeepay.thirdparty.channel.yspay.model.YsCardType;
import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignRsaUtil;
import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignSmUtil;
import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit;
import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService;
import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.FileInputStream;
import java.util.Map;

/**
 * 银盛支付 回调接口实现类
 *
 * @author xiaoyu
 *
 * @date 2022/4/15 10:23
 */
@Service
@Slf4j
public class YspayChannelNoticeService extends AbstractChannelNoticeService {

    @Override
    public String getIfCode() {
        return CS.IF_CODE.YSPAY;
    }

    @Override
    public MutablePair<String, Object> parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) {

        try {
            JSONObject reqParamJSON = getReqParamJSON();
            String payOrderId = reqParamJSON.getString("out_trade_no");
            return MutablePair.of(payOrderId, reqParamJSON);
        } catch (Exception e) {
            log.error("error", e);
            throw ResponseException.buildText("ERROR");
        }
    }



    @Override
    public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) {
        try {
            JSONObject respJson = (JSONObject) JSONObject.toJSON(params);
            boolean verifyResult = verifyParams(respJson, mchAppConfigContext, payOrder);
            // 验证参数失败
            if(!verifyResult){
                throw ResponseException.buildText("error");
            }
            //验签成功后判断上游订单状态
            ResponseEntity okResponse = textResp("success");
            ChannelRetMsg result = new ChannelRetMsg();
            result.setResponseEntity(okResponse);
            result.setChannelBizData(respJson);
            result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
            result.setChannelOrderId(respJson.getString("trade_no"));
            //如果是支付宝 则需要去除前两位
            result.setPlatformOrderNo(respJson.getString("channel_recv_sn"));
            //银盛订单号特殊处理
            if(CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(payOrder.getWayCodeType())){
                result.setPlatformOrderNo(result.getPlatformOrderNo().substring(2));
            }
            YsCardType val = YsCardType.getVal(respJson.getString("card_type"));
            if(val == null){
                result.setDrType(CS.DrType.OTHER.getType());
            }else{
                switch (val){
                    case CREDIT:
                        result.setDrType(CS.DrType.CREDIT.getType());
                        break;
                    case DEBIT:
                        result.setDrType(CS.DrType.DEBIT.getType());
                        break;
                }
            }
            result.setPlatformMchOrderNo(respJson.getString("channel_send_sn"));
            return result;
        } catch (Exception e) {
            log.error("error", e);
            throw ResponseException.buildText("ERROR");
        }
    }


    /**
     * 验证银盛支付通知参数
     * @return
     */
    public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext, PayOrder payOrder) {
        try {
            String logPrefix = "【处理[银盛]支付回调】";

            log.info("{} 回调参数: jsonParams：{}", logPrefix, jsonParams);
            String sign = jsonParams.getString("sign");
            String tradeStatus = jsonParams.getString("trade_status");
            Map<String, String> paramsMap = jsonParams.toJavaObject(Map.class);
            if (StringUtils.isEmpty(sign)) {
                log.info("验签参数为空：sign：{}", sign);
                return false;
            }

            if (!YspayKit.TRADE_SUCCESS.equals(tradeStatus)) {
                log.info("订单状态未支付成功：tradeStatus：{}", tradeStatus);
                return false;
            }

            // 校验支付回调
            ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class);
            YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), payOrder.getIfCode());

            // 证书地址
            ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class);
            String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile());
            boolean verifyResult = false;
            if ("RSA".equals(isvParams.getSignType())) {
                FileInputStream fileInputStream = new FileInputStream(channelCertConfigKitBean.getCertFile(isvParams.getPublicKeyFile()));
                verifyResult = SignRsaUtil.asynVerifyYsRsa(fileInputStream, paramsMap);
            }else if ("SM".equals(isvParams.getSignType())){
                verifyResult = SignSmUtil.asynVerifyYsSm(certFilePath, paramsMap);
            }else {
                log.error("未识别的签名类型");
            }

            //验签失败
            if(!verifyResult) {
                log.info("{} 验签失败！ 回调参数：parameter = {}, certFilePath={} ", logPrefix, jsonParams, certFilePath);
                return false;
            }
            return true;
        }catch (Exception e) {
            log.error("验证签名异常", e);
            return false;
        }
    }
}
