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

import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
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.model.rqrs.msg.DivisionChannelNotifyModel;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionRecordChannelNotifyService;
import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignRsaUtil;
import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignSmUtil;
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.HashMap;
import java.util.List;
import java.util.Map;

/**
 * TODO
 *
 * @author crystal
 * @date 2024/1/28 14:56
 */
@Service
@Slf4j
public class YspayDivisionRecordChannelNotifyService extends AbstractDivisionRecordChannelNotifyService {

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

    @Override
    public MutablePair<String, Object> parseParams(HttpServletRequest request) {
        JSONObject reqParamJSON = getReqParamJSON();
        log.info("【银盛分账】异步通知参数:{}", reqParamJSON);
        return MutablePair.of(reqParamJSON.getString("out_trade_no"), reqParamJSON);
    }

    @Override
    public DivisionChannelNotifyModel doNotify(HttpServletRequest request, Object params, List<? extends PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext) {
        JSONObject notifyData = (JSONObject) params;
        boolean verifyResult = verifyParams(notifyData, mchAppConfigContext);
        if(!verifyResult){
            log.info("银盛分账回调签名校验失败");
            throw ResponseException.buildText("error");
        }
        //验签成功后判断上游订单状态
        ResponseEntity okResponse = textResp("success");
        DivisionChannelNotifyModel result = new DivisionChannelNotifyModel();
        String division_status_code = notifyData.getString("division_status_code");
        //分账处理中
        ChannelRetMsg.ChannelState channelState;
        if("00".equals(division_status_code) || "02".equals(division_status_code) || "03".equals(division_status_code)){
            channelState = ChannelRetMsg.ChannelState.CONFIRM_SUCCESS;
        }else if("01".equals(division_status_code)){
            channelState = ChannelRetMsg.ChannelState.WAITING;
        }else if("99".equals(division_status_code)){
            channelState = ChannelRetMsg.ChannelState.CONFIRM_FAIL;
        }else{
            channelState = ChannelRetMsg.ChannelState.UNKNOWN;
        }
        String note = notifyData.getString("note");
        Map<Long, ChannelRetMsg> recordResultMap = new HashMap<>();
        for (PayOrderDivisionRecord pdr:recordList) {
            ChannelRetMsg channelRetMsg = new ChannelRetMsg();
            channelRetMsg.setChannelState(channelState);
            channelRetMsg.setChannelErrMsg(note);
            channelRetMsg.setChannelOriginResponse(notifyData.getString("detailResults"));
            recordResultMap.put(pdr.getRecordId(),channelRetMsg);
        }
        result.setRecordResultMap(recordResultMap);
        result.setApiRes(okResponse);
        return result;
    }

    /**
     * 校验签名
     * @param notifyData
     * @param mchAppConfigContext
     * @return
     */
    /**
     * 验证银盛支付通知参数
     * @return
     */
    public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) {
        try {
            String logPrefix = "【处理[银盛]分账回调】";
            log.info("{} 回调参数: jsonParams：{}", logPrefix, jsonParams);
            String sign = jsonParams.getString("sign");
            Map<String, String> paramsMap = jsonParams.toJavaObject(Map.class);
            if (StringUtils.isEmpty(sign)) {
                log.info("验签参数为空：sign：{}", sign);
                return false;
            }
            // 校验支付回调
            ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class);
            YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), 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;
        }
    }

}
