package cn.pluss.platform.ys.pay;

import cn.pluss.platform.api.ResultCode;
import cn.pluss.platform.channel.MakeMoneyService;
import cn.pluss.platform.constants.Constant;
import cn.pluss.platform.dto.MemberScanPayDTO;
import cn.pluss.platform.dto.MerChantOrderDTO;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.merchantOrder.MerchantOrderService;
import cn.pluss.platform.pay.PayService;
import cn.pluss.platform.util.*;
import cn.pluss.platform.ys.YsConfig;
import cn.pluss.platform.ys.YsService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 银盛支付实现类
 */
@Service("ysPayService")
@Slf4j
public class YsPayServiceImpl implements PayService {


    @Resource
    private YsService ysService;

    @Resource
    private YsConfig ysConfig;

    @Setter(onMethod_ = {@Autowired,@Lazy})
    private MakeMoneyService makeMoneyService;

    @Setter(onMethod_ = {@Autowired,@Lazy})
    private MerchantOrderService merchantOrderService;
    /**
     * 商家被扫
     * @param order
     * @param channel
     * @return
     */
    @Override
    public JSONObject tradePay(MerchantOrder order, MerchantChannelStatus channel,MerchantBaseInfo merchant) {
        int flag = new BigDecimal(String.valueOf(order.getConsumeFee())).compareTo(new BigDecimal("0.01"));
        MsgException.check(flag <= 0,"订单金额必须大于0.01元！");
        //小程序
        String url = ysConfig.UNI_JSAPI_PAY;
        if("9".equals(order.getOrderType()) || "10".equals(order.getOrderType())){
            url = ysConfig.WX_APPLETS_PAY;
        }else{
            if(Constant.PAY_TYPE_ALIPAY.equals(order.getPayTypeCode())){
                url = ysConfig.ALI_JSAPI_PAY;
            }else if(Constant.PAY_TYPE_WECHAT.equals(order.getPayTypeCode())){
                url = ysConfig.WX_JSAPI_PAY;
            }
        }

        JSONObject reqData = converParameter(order,channel);

        JSONObject respones = ysService.requestApi(url, reqData,YsService.TYPE_PAY);

        JSONObject rData = checkResultParams(respones);

        JSONObject object = new JSONObject(3);

        object.put("code",ResultCode.SUCCESS.code());

        JSONObject payData = new JSONObject();

        JSONObject pData = rData.getJSONObject("payData");
        if(Constant.PAY_TYPE_WECHAT.equals(order.getPayTypeCode())) {
//            payData.put("prepayId",pData.get("prepayId"));
            payData.put("payAppId",pData.get("appId"));
            payData.put("payTimeStamp",pData.get("timeStamp"));
            payData.put("paynonceStr",pData.get("nonceStr"));
            payData.put("payPackage",pData.get("package"));
            payData.put("paySignType",pData.get("signType"));
            payData.put("paySign",pData.get("paySign"));
//            payData.put("partnerId",pData.get("partnerId"));
        }else if(Constant.PAY_TYPE_ALIPAY.equals(order.getPayTypeCode())){
            payData.put("source",pData.get("tradeNO"));
        }else{
            payData.put("redirectUrl",pData.get("redirectUrl"));
        }
        payData.put("channel",channel.getChannel());
        order.setTransNo(StringUtil.isEmpty(rData.getString("ysTradeNo")) ? "" : rData.getString("ysTradeNo"));
        object.put("payData",payData);
        return object;
    }

    /**
     * 组装请求业务参数
     * @param order
     * @param channel
     * @return
     */

    public JSONObject converParameter(MerchantOrder order, MerchantChannelStatus channel) {
        JSONObject reqData = new JSONObject(10);
        reqData.put("merchantNo",channel.getMerchantId());
        if(Constant.PAY_TYPE_WECHAT.equals(order.getPayTypeCode())){
            reqData.put("openId",order.getMercUserId());
            reqData.put("appId", ParametersUtil.APPID);
        }else{
            reqData.put("userId",order.getMercUserId());
        }
        reqData.put("backUrl", ParametersUtil.domain+"/wap/notify/ysCallBack");
        reqData.put("merchantOrderNo",order.getOrderNumber());
        reqData.put("tradeTime", DateUtils.formatDateDefault(new Date(),"yyyyMMddHHmmss"));
        reqData.put("tradeAmount",new BigDecimal(String.valueOf(order.getConsumeFee())).setScale(2));
        reqData.put("orderDesc",StringUtil.isEmpty(order.getRemark()) ? "下单" : order.getRemark());
        return reqData;
    }

    /**
     * 商家主扫
     * @param merchantOrderDTO
     * @param order
     * @return
     */
    @Override
    public JSONObject tradePay(MerChantOrderDTO merchantOrderDTO, MerchantOrder order) {

        int flag = new BigDecimal(String.valueOf(order.getConsumeFee())).compareTo(new BigDecimal("0.01"));

        MsgException.check(flag <= 0,"订单金额必须大于0.01元！");

        String url = ysConfig.UNI_BARCODE_PAY;
        if(Constant.PAY_TYPE_ALIPAY.equals(merchantOrderDTO.getPayTypeCode())){
            url = ysConfig.ALI_BARCODE_PAY;
        }else if(Constant.PAY_TYPE_WECHAT.equals(merchantOrderDTO.getPayTypeCode())){
            url = ysConfig.WX_BARCODE_PAY;
        }
        JSONObject reqData = new JSONObject();
        reqData.put("merchantNo",merchantOrderDTO.getChannelNo());
        reqData.put("authCode",merchantOrderDTO.getAuthCode());
        reqData.put("merchantOrderNo",order.getOrderNumber());
        reqData.put("tradeTime",DateUtils.formatDateDefault(new Date(),"yyyyMMddHHmmss"));
        reqData.put("tradeAmount",new BigDecimal(String.valueOf(order.getConsumeFee())).setScale(2));
        reqData.put("orderDesc", StringUtil.isEmpty(order.getRemark()) ? "下单" : order.getRemark());
        if(Constant.PAY_TYPE_YSFPAY.equals(order.getPayTypeCode())){
            reqData.put("terminalNo", StringUtil.genRandomNum(8));
        }
        JSONObject respones = ysService.requestApi(url, reqData,YsService.TYPE_PAY);

        JSONObject rData = checkResultParams(respones);

        JSONObject result = new JSONObject();

        //通道交易流水号 支付宝或微信交易流水号
        result.put("channelOrderNo",rData.getString("channelRecvNo"));
        result.put("transNo",rData.getString("ysTradeNo"));
        if(YsConfig.YS_RESULT_WAITPAY_CODE.equals(rData.getString("status"))){
            result.put("code", ResultCode.TRANSUNKNOW.code());
            result.put("msg","等待支付中...");
            result.put("payStatus","7");
        }else{
            result.put("code",ResultCode.SUCCESS.code());
            result.put("payStatus","1");
            result.put("msg","请求成功！");
            String payTime = rData.getString("payTime");
            result.put("payTime",DateUtils.parse(payTime,"yyyyMMddHHmmss"));
        }
        return result;
    }

    /**
     * 校验返回参数
     * @param respones
     */
    private JSONObject checkResultParams(JSONObject respones) {
        if(YsConfig.YS_RESULT_FAIL_CODE.equals(respones.getString("responseCode"))){
            MsgException.throwException(respones.getString("responseMeg"));
        }
        JSONObject respData = respones.getJSONObject("bizResponseJson");
        if(YsConfig.YS_RESULT_PAY_FAIL_CODE.equals(respData.getString("status")) ||
                YsConfig.YS_RESULT_UNKNOW_CODE.equals(respData.getString("status"))){
            MsgException.throwException(respData.getString("statusMeg"));
        }
        return respData;
    }

    /**
     * 商家退款
     * @param order
     * @param mchNo
     * @return
     */
    @Override
    public Map<String, Object> refundPay(MerchantOrder order, String mchNo) {
        Map<String,Object> result = new HashMap<>(4);

        JSONObject reqData = new JSONObject();
        Double amt = new BigDecimal(String.valueOf(order.getConsumeFee())).setScale(2).doubleValue();
        String refundNo = "YSR"+StringUtil.getBillno();
        reqData.put("merchantNo",mchNo);
        reqData.put("origMerchantOrderNo",order.getOrderNumber());
        reqData.put("origAmount",amt);
        reqData.put("refundOrderNo",refundNo);
        reqData.put("refundAmount",amt);

        JSONObject respones = ysService.requestApi(ysConfig.REFUND_PAY, reqData, YsService.TYPE_PAY);

        JSONObject respData = checkResultParams(respones);

        result.put("refundNo",refundNo);
        result.put("status","3");
        result.put("code",ResultCode.FAIL.code());
        if(YsConfig.YS_RESULT_PAY_SUCCESS_CODE.equals(respData.getString("status"))){
            result.put("msg","退款成功！");
            result.put("data",respData);
            result.put("status","1");
            result.put("code",ResultCode.SUCCESS.code());
            return result;
        }else if(YsConfig.YS_RESULT_ACCEPT_CODE.equals(respData.getString("status"))){
            result.put("msg","退款中！");
            result.put("data",respData);
            result.put("status","2");
            result.put("code",ResultCode.TRANSUNKNOW.code());
            return result;
        }
        result.put("msg",respData.getString("statusMeg"));
        return result;
    }

    /**
     * 交易查询
     * @param order
     * @return
     */
    @Override
    public JSONObject tradeQuery(MerchantOrder order,String mchId) {

        JSONObject result = new JSONObject(6);
        JSONObject reqData = new JSONObject();
        reqData.put("merchantNo",mchId);
        reqData.put("merchantOrderNo",order.getOrderNumber());
        try {
            JSONObject respones = ysService.requestApiCommon(ysConfig.PAY_ORDER_QUERY, reqData, ysService.TYPE_PAY);
            String status = respones.getString("status");
            if(YsConfig.YS_RESULT_PAY_SUCCESS_CODE.equals(status)){
                String ysTradeNo = respones.getString("ysTradeNo");
                String payTime = respones.getString("payTime");
                String transactionId = respones.getString("channelRecvNo");//支付渠道单号
                String buyerId = respones.getString("buyerId");
                if(StringUtil.isNotEmpty(transactionId)){
                    transactionId = transactionId.substring(2);
                }
                result.put("channelOrderNo",transactionId);
                result.put("payTime",DateUtils.parse(payTime,"yyyyMMddHHmmss"));
                result.put("transNo",ysTradeNo);
                result.put("code", ResultCode.SUCCESS.code());
                result.put("payStatus", "1");
                result.put("msg", "查询成功！");
                result.put("buyerId", buyerId);
                return result;
            }else if(!"waitpay".equals(status)){
                result.put("code", ResultCode.SUCCESS.code());
                result.put("payStatus", "0");
                result.put("msg", "查询成功");
                result.put("remark",status);
                return result;
            }
            result.put("code", ResultCode.SUCCESS.code());
            result.put("payStatus", "5");
            result.put("msg", "查询成功");
            return result;
        }catch (Exception e){
            result.put("code",ResultCode.FAIL.code());
            result.put("msg",e.getMessage());
            return result;
        }
    }

    /**
     * 退款查询
     * @param refundOrder
     * @return
     */
    @Override
    public JSONObject refundQuery(MerchantRefundOrder refundOrder) {
        JSONObject result = new JSONObject(3);
        JSONObject reqData = new JSONObject();
        reqData.put("merchantNo",refundOrder.getChannelNo());
        reqData.put("refundOrderId",refundOrder.getRefundNo());
        try {
            JSONObject respones = ysService.requestApiCommon(ysConfig.REFUND_QUERY, reqData, ysService.TYPE_PAY);
            String status = respones.getString("status");
            if(YsConfig.YS_RESULT_PAY_SUCCESS_CODE.equals(status)){
                result.put("status","1");
                result.put("refundTime",respones.getString("refundPayTime"));
            }else if(YsConfig.YS_RESULT_ACCEPT_CODE.equals(status)){
                result.put("status","2");
            }else{
                result.put("status","3");
            }
            result.put("code",ResultCode.SUCCESS.code());
            result.put("msg",respones.getString("statusMeg"));
            return result;
        }catch (Exception e){
            log.error("==============>【银盛】退款订单查询异常，异常信息：{}<==================",e.getMessage());
            result.put("code",ResultCode.FAIL.code());
            result.put("msg","退款查询异常！");
            return result;
        }
    }

    /**
     * 订单关闭
     * @param orderNumber
     * @param channelNo
     * @return
     */
    @Override
    public Map<String, Object> closeOrder(String orderNumber, String channelNo) {
        return null;
    }

    /**
     * 获取用户id
     * @param memberScanPayDTO
     * @param channel
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, Object> getWxOpenId(MemberScanPayDTO memberScanPayDTO, MerchantChannelStatus channel) throws Exception {
        return null;
    }

    /**
     * 获取银联用户标识
     * @param userAuthCode
     * @param paymentApp
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, Object> getUnionInfo(String userAuthCode, String paymentApp,String merchantId) throws Exception {

        if(StringUtil.isEmpty(userAuthCode)){
            throw new MsgException("授权码不能为空！");
        }
        if(StringUtil.isEmpty(paymentApp)){
            throw new MsgException("银联标识不能为空！");
        }

        Map<String,Object> result = new HashMap<>(2);

        JSONObject reqData = new JSONObject(2);

        reqData.put("userAuthCode",userAuthCode);
        reqData.put("appUpIdentifier",paymentApp);
        JSONObject respones  = ysService.requestApiCommon(ysConfig.GET_UNION_USER_ID, reqData,YsService.TYPE_PAY);
        if(ysConfig.YS_RESULT_FAIL_CODE.equals(respones.getString("status"))){
            throw new MsgException(respones.getString("statusMeg"));
        }
        reqData.put("data",respones.getString("unionUserId"));

        result.put("data",reqData);
        result.put("code","1");
        result.put("msg","获取成功");
        return result;
    }

    @Override
    public String payNotifyCallBack(Map<String, String> params) {
        if(params.size() <= 0){
            return YsConfig.YS_RESULT_FAIL_CODE;
        }
        String sign = params.get("sign");
        params.remove("sign");
        JSONObject paramsData = JSONObject.parseObject(JSONObject.toJSONString(params));
        String signContent = SignUtils.getYSSignContent(paramsData);
        boolean flag = false;
        try {
            flag = RSAUtils.checkSign(ysConfig.getPubKey(),signContent,sign);
        } catch (Exception e) {
            log.info("=========================>【银盛】校验签名异常，异常信息:{}<=====================",e.getMessage());
            e.printStackTrace();
        }
        if(!flag){
            log.info("=========================>【银盛】异步通知签名校验失败<=====================");
            return YsConfig.YS_RESULT_FAIL_CODE;
        }
        String serviceNo = params.get("serviceNo");
        JSONObject respData = JSONObject.parseObject(params.get("bizResponseJson"));
        //提现异步通道
        if("withdrawNotify".equals(serviceNo)){
            withdrawNotify(respData);
        }else{
            //支付异步通道
            payNotify(respData);
        }
        return YsConfig.RESULT_SUCCESS_CODE;
    }

    /**
     * @description:交易异步通知处理
     * @date: 2021/8/20 10:22
     */
    private String payNotify(JSONObject respData) {
        String ysTradeNo = respData.getString("ysTradeNo");  //随行付交易流水号，32位
        //String merchantNo = respData.getString("merchantNo");  //商户编号
        String ordNo = respData.getString("merchantOrderNo");  //商户单号
        String payTime = respData.getString("payTime");  //交易时间 yyyyMMddHHmmss
        //渠道订单号
        String channelSendNo = respData.getString("channelSendNo");  //发往渠道流水
        String channelRecvNo = respData.getString("channelRecvNo").substring(2);  //渠道响应流水
        String settlementAmt = respData.getString("settlementAmt");  //结算金额
        String srcFee = respData.getString("srcFee");  //发起方手续费
        String payeeFee = respData.getString("payeeFee");  //收款方手续费
        String payerFee = respData.getString("payerFee");  //付款方手续费,代付交易使用
        //支付成功
        QueryWrapper<MerchantOrder> queryWrapper = new QueryWrapper<MerchantOrder>().eq("orderNumber",ordNo);

        Date payDate = new Date();
        try {
            payDate = new SimpleDateFormat("yyyyMMddHHmmss").parse(payTime);
        } catch (ParseException e) {
            log.info("====================>【银盛】回调时间格式化异常，待转换的时间格式:{}<====================",payTime);
        }
        MerchantOrder order = merchantOrderService.getOne(queryWrapper);
        if(order == null){
            log.error("====================>【银盛】支付成功回调订单号查询，查询的订单为空：订单号：{}<====================",ordNo);
            return YsConfig.RESULT_SUCCESS_CODE;
        }
        order.setEnterFee(new BigDecimal(settlementAmt).setScale(2).doubleValue());
        order.setTransDt(payDate);
        order.setTransNo(ysTradeNo);
        order.setThirdTransNo(channelRecvNo);
        merchantOrderService.updateOrderAndCreateProfit(order);
        return YsConfig.RESULT_SUCCESS_CODE;
    }

    /**
     * @description:提现异步通知处理
     * @date: 2021/8/20 10:24
     * @param respData: 回调业务参数
     * @return java.lang.String
     */
    private String withdrawNotify(JSONObject respData) {
        String ordNo = respData.getString("merchantOrderNo");  //商户单号
        MakeMoney makeMoney = makeMoneyService.getOne(new QueryWrapper<MakeMoney>().eq("billId", ordNo));
        if(makeMoney == null){
            log.info("======【银盛提现回调】========>提现单号：{}数据不存在，请核实<================",ordNo);
            return YsConfig.RESULT_SUCCESS_CODE;
        }
        if(!"0".equals(makeMoney.getState())){
            log.info("======【银盛提现回调】========>提现单号：{}数据打款状态不为打款中，无需打款状态<================",ordNo);
            return YsConfig.RESULT_SUCCESS_CODE;
        }
        String status = respData.getString("status");
        if(YsConfig.RESULT_SUCCESS_CODE.equals(status) || YsConfig.YS_RESULT_ACCEPT_CODE.equals(status)){
            if(YsConfig.RESULT_SUCCESS_CODE.equals(status)){
                makeMoney.setState("1");
            }else{
                makeMoney.setState("0");
            }
            makeMoney.setRemark(respData.getString("statusMeg"));
            makeMoney.setChannelNo(respData.getString("ysTradeNo"));
            makeMoney.setMercFee(respData.getBigDecimal("payeeFee").setScale(2).doubleValue());
        }else{
            if(YsConfig.YS_RESULT_DFREVERSE_CODE.equals(respData.getString("status"))){
                makeMoney.setState("2");
            }else{
                makeMoney.setState("-1");
            }
            makeMoney.setThirdStatus(status);
            makeMoney.setFailReason(respData.getString("statusMeg"));
        }
        makeMoneyService.updateById(makeMoney);
        return YsConfig.RESULT_SUCCESS_CODE;
    }

    @Override
    public String tradePayWap(MerchantOrder order, MerchantChannelStatus channel) {
        return null;
    }

    @Override
    public JSONObject getUnionAccountUrl(JSONObject reqData) {
        return null;
    }

    @Override
    public JSONObject jftPay(JftReceiptOrder order, JftMercBaseInfo jftMerc, JftMercPaymentChannel jftChannel) {
        return null;
    }
}
