package com.yc.ship.module.trade.service.pay.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yc.ship.framework.common.exception.ServiceException;
import com.yc.ship.framework.common.util.servlet.ServletUtils;
import com.yc.ship.module.trade.controller.admin.order.vo.order.PayOrderReqVO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeMchInfoDO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeOrderPayDO;
import com.yc.ship.module.trade.dal.dataobject.refund.RefundDO;
import com.yc.ship.module.trade.dal.dataobject.refund.RefundRecordDO;
import com.yc.ship.module.trade.framework.common.ClientInfo;
import com.yc.ship.module.trade.framework.common.PayDigestUtil;
import com.yc.ship.module.trade.framework.common.PayUtil;
import com.yc.ship.module.trade.service.pay.PayPlatService;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Map;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.PAY_PLAT_UNKNOWN_EXCEPTION;


/**
 * &#064;Description ：支付平台service实现
 * &#064;Author ：qsl
 * &#064;Date ：2025/7/15 11:18
 * @author qsl
 */
@Service
@Slf4j
public class PayPlatServiceImpl implements PayPlatService {

    @Value("${huilv.pay.base-url}")
    public String baseUrl;
    @Value("${huilv.pay.pay-notify-url}")
    public String payNotifyUrl;
    @Value("${huilv.pay.refund-notify-url}")
    public String refundNotifyUrl;

    public static final String SUCCESS = "SUCCESS";

    @Override
    public JSONObject createPayOrder(PayOrderReqVO payOrderReqVO, TradeOrderPayDO tradeOrderPayDO, TradeMchInfoDO tradeMchInfoDO) {
        try {
            JSONObject paramMap = new JSONObject();
            //支付平台主商户号
            String customMchId = tradeOrderPayDO.getMerchantNo();
            paramMap.set("channelId", tradeOrderPayDO.getChannelId());
            paramMap.set("goods", payOrderReqVO.getPayParams().getParam());
            paramMap.set("mchId", customMchId);
            // 商户订单号
            paramMap.set("mchOrderNo", tradeOrderPayDO.getId());
            //分
            paramMap.set("amount", tradeOrderPayDO.getPayAmount().multiply(new BigDecimal(100)).intValue());
            // 币种, cny-人民币
            paramMap.set("currency", "cny");
            // 用户地址,IP或手机号
            payOrderReqVO.getPayParams().setClientIp(ServletUtils.getClientIP());
            paramMap.set("clientIp",  payOrderReqVO.getPayParams().getClientIp());

            paramMap.set("msgType", payOrderReqVO.getPayParams().getMsgType());
            //个人网银使用
            paramMap.set("channelType", payOrderReqVO.getPayParams().getChannelType());
            paramMap.set("returnUrl", payOrderReqVO.getPayParams().getPayReturnUrl());
            //支付码
            if(StringUtil.isNotEmpty(payOrderReqVO.getPayCode())) {
                paramMap.set("payCode", payOrderReqVO.getPayCode());
            }
            // 主账号金额
            paramMap.set("platformAmount", tradeOrderPayDO.getPayAmount().multiply(new BigDecimal(100)).intValue());

            //设备--操作系统
            ClientInfo clientInfo = new ClientInfo(ServletUtils.getUserAgent());
            payOrderReqVO.getPayParams().setDevice(clientInfo.getOSName());
            paramMap.set("device", payOrderReqVO.getPayParams().getDevice());

            paramMap.set("subject",  payOrderReqVO.getPayParams().getSubject());
            paramMap.set("body",  payOrderReqVO.getPayParams().getBody());
            // 回调URL
            paramMap.set("notifyUrl", payNotifyUrl);

            //扩展参数1
            paramMap.set("param1", tradeOrderPayDO.getPaymentType());
            //扩展参数2
            paramMap.set("param2", payOrderReqVO.getPayParams().getParam());
            //过期时间
            paramMap.set("expireTime", "1800");
            if( payOrderReqVO.getPayParams().getExtra() == null){
                payOrderReqVO.getPayParams().setExtra(new JSONObject());
            }
            JSONObject extra = payOrderReqVO.getPayParams().getExtra();
            extra.set("openId", tradeOrderPayDO.getOpenId());
            //ALIPAY_WAP需要的参数
            extra.set("productId", payOrderReqVO.getPayParams().getProductId());
            extra.set("tradeChannel", payOrderReqVO.getPayParams().getTradeChannel());
            extra.set("tranCode", payOrderReqVO.getPayParams().getTranCode());

            extra.set("appId", payOrderReqVO.getPayParams().getAppId());

            // 附加参数 经纬度信息也在extra参数中
            paramMap.set("extra", extra);
            String reqSign = PayDigestUtil.getSign(paramMap, tradeMchInfoDO.getReqKey());
            // 签名
            paramMap.set("sign", reqSign);
            String reqJsonStr = paramMap.toString();
            String reqDataEncode = "params=" + URLEncoder.encode(reqJsonStr, "UTF-8");
            String reqData = "params=" +reqJsonStr;
            log.info("请求支付中心下单接口,请求数据:{}", reqData);
            String url = baseUrl + "/pay/create_order?";
            String result = PayUtil.call4Post(url + reqDataEncode);
            log.info("请求支付中心下单接口（{}{}）,响应数据:{}", url, reqDataEncode, result);
            Map<String, Object> retMap = JSONUtil.parseObj(result);
            if (StrUtil.equals(SUCCESS, MapUtils.getString(retMap, "retCode"))) {
                // 补充参数
                paramMap.set("payOrderId", MapUtils.getString(retMap, "payOrderId"));
                if (retMap.containsKey("payOrder")) {
                    Object payOrderStr = retMap.get("payOrder");
                    JSONObject payOrder = JSONUtil.parseObj(payOrderStr);
                    if (!payOrder.isEmpty()) {
                        retMap.put("payOrder", paramMap);
                    }
                }
                //非银联支付返回的支付二维码
                if (retMap.get("payUrl") == null && retMap.get("codeUrl") != null) {
                    retMap.put("payUrl", retMap.get("codeUrl"));
                }
                retMap.put("channelId", paramMap.getStr("channelId"));
            }
            retMap.put("mainMid", customMchId);
            retMap.put("channelId", paramMap.getStr("channelId"));
            return JSONUtil.parseObj(retMap);
        } catch (ServiceException ex) {
            throw ex;
        } catch (Exception ex) {
            log.error("调用支付平台异常",ex);
            throw exception(PAY_PLAT_UNKNOWN_EXCEPTION);
        }
    }

    @Override
    public JSONObject createDeposiPayOrder(PayOrderReqVO payOrderReqVO, TradeOrderPayDO tradeOrderPayDO, TradeMchInfoDO tradeMchInfoDO) {
        try {
            JSONObject paramMap = new JSONObject();
            //支付平台主商户号
            String customMchId = tradeOrderPayDO.getMerchantNo();
            paramMap.set("channelId", tradeOrderPayDO.getChannelId());
            paramMap.set("goods", payOrderReqVO.getPayParams().getParam());
            paramMap.set("mchId", customMchId);
            // 商户订单号
            paramMap.set("mchOrderNo", tradeOrderPayDO.getId());
            //分
            paramMap.set("amount", tradeOrderPayDO.getPayAmount().multiply(new BigDecimal(100)).intValue());
            // 币种, cny-人民币
            paramMap.set("currency", "cny");
            // 用户地址,IP或手机号
            payOrderReqVO.getPayParams().setClientIp(ServletUtils.getClientIP());
            paramMap.set("clientIp",  payOrderReqVO.getPayParams().getClientIp());

            paramMap.set("msgType", payOrderReqVO.getPayParams().getMsgType());
            //个人网银使用
            paramMap.set("channelType", payOrderReqVO.getPayParams().getChannelType());
            paramMap.set("returnUrl", payOrderReqVO.getPayParams().getPayReturnUrl());
            //支付码
            if(StringUtil.isNotEmpty(payOrderReqVO.getPayCode())) {
                paramMap.set("payCode", payOrderReqVO.getPayCode());
            }
            // 主账号金额
            paramMap.set("platformAmount", tradeOrderPayDO.getPayAmount().multiply(new BigDecimal(100)).intValue());

            //设备--操作系统
            ClientInfo clientInfo = new ClientInfo(ServletUtils.getUserAgent());
            payOrderReqVO.getPayParams().setDevice(clientInfo.getOSName());
            paramMap.set("device", payOrderReqVO.getPayParams().getDevice());

            paramMap.set("subject",  payOrderReqVO.getPayParams().getSubject());
            paramMap.set("body",  payOrderReqVO.getPayParams().getBody());
            // 回调URL
            paramMap.set("notifyUrl", payNotifyUrl.replace("payNotify", "deposiPayNotify"));

            //扩展参数1
            paramMap.set("param1", tradeOrderPayDO.getPaymentType());
            //扩展参数2
            paramMap.set("param2", payOrderReqVO.getPayParams().getParam());
            //过期时间
            paramMap.set("expireTime", "1800");
            if( payOrderReqVO.getPayParams().getExtra() == null){
                payOrderReqVO.getPayParams().setExtra(new JSONObject());
            }
            JSONObject extra = payOrderReqVO.getPayParams().getExtra();
            extra.set("openId", tradeOrderPayDO.getOpenId());
            //ALIPAY_WAP需要的参数
            extra.set("productId", payOrderReqVO.getPayParams().getProductId());
            extra.set("tradeChannel", payOrderReqVO.getPayParams().getTradeChannel());
            extra.set("tranCode", payOrderReqVO.getPayParams().getTranCode());

            extra.set("appId", payOrderReqVO.getPayParams().getAppId());

            // 附加参数 经纬度信息也在extra参数中
            paramMap.set("extra", extra);
            String reqSign = PayDigestUtil.getSign(paramMap, tradeMchInfoDO.getReqKey());
            // 签名
            paramMap.set("sign", reqSign);
            String reqJsonStr = paramMap.toString();
            String reqDataEncode = "params=" + URLEncoder.encode(reqJsonStr, "UTF-8");
            String reqData = "params=" +reqJsonStr;
            log.info("请求支付中心下单接口,请求数据:{}", reqData);
            String url = baseUrl + "/pay/create_order?";
            String result = PayUtil.call4Post(url + reqDataEncode);
            log.info("请求支付中心下单接口（{}{}）,响应数据:{}", url, reqDataEncode, result);
            Map<String, Object> retMap = JSONUtil.parseObj(result);
            if (StrUtil.equals(SUCCESS, MapUtils.getString(retMap, "retCode"))) {
                // 补充参数
                paramMap.set("payOrderId", MapUtils.getString(retMap, "payOrderId"));
                if (retMap.containsKey("payOrder")) {
                    Object payOrderStr = retMap.get("payOrder");
                    JSONObject payOrder = JSONUtil.parseObj(payOrderStr);
                    if (!payOrder.isEmpty()) {
                        retMap.put("payOrder", paramMap);
                    }
                }
                //非银联支付返回的支付二维码
                if (retMap.get("payUrl") == null && retMap.get("codeUrl") != null) {
                    retMap.put("payUrl", retMap.get("codeUrl"));
                }
                retMap.put("channelId", paramMap.getStr("channelId"));
            }
            retMap.put("mainMid", customMchId);
            retMap.put("channelId", paramMap.getStr("channelId"));
            return JSONUtil.parseObj(retMap);
        } catch (ServiceException ex) {
            throw ex;
        } catch (Exception ex) {
            log.error("调用支付平台异常",ex);
            throw exception(PAY_PLAT_UNKNOWN_EXCEPTION);
        }
    }

    @Override
    public JSONObject createBcPayOrder(PayOrderReqVO payOrderReqVO, TradeOrderPayDO tradeOrderPayDO, TradeMchInfoDO tradeMchInfoDO) {
        try {
            JSONObject paramMap = new JSONObject();
            //支付平台主商户号
            String customMchId = tradeOrderPayDO.getMerchantNo();
            paramMap.set("channelId", tradeOrderPayDO.getChannelId());
            paramMap.set("goods", payOrderReqVO.getPayParams().getParam());
            paramMap.set("mchId", customMchId);
            // 商户订单号
            paramMap.set("mchOrderNo", tradeOrderPayDO.getId());
            //分
            paramMap.set("amount", tradeOrderPayDO.getPayAmount().multiply(new BigDecimal(100)).intValue());
            // 币种, cny-人民币
            paramMap.set("currency", "cny");
            // 用户地址,IP或手机号
            payOrderReqVO.getPayParams().setClientIp(ServletUtils.getClientIP());
            paramMap.set("clientIp",  payOrderReqVO.getPayParams().getClientIp());

            paramMap.set("msgType", payOrderReqVO.getPayParams().getMsgType());
            //个人网银使用
            paramMap.set("channelType", payOrderReqVO.getPayParams().getChannelType());
            paramMap.set("returnUrl", payOrderReqVO.getPayParams().getPayReturnUrl());
            //支付码
            if(StringUtil.isNotEmpty(payOrderReqVO.getPayCode())) {
                paramMap.set("payCode", payOrderReqVO.getPayCode());
            }
            // 主账号金额
            paramMap.set("platformAmount", tradeOrderPayDO.getPayAmount().multiply(new BigDecimal(100)).intValue());

            //设备--操作系统
            ClientInfo clientInfo = new ClientInfo(ServletUtils.getUserAgent());
            payOrderReqVO.getPayParams().setDevice(clientInfo.getOSName());
            paramMap.set("device", payOrderReqVO.getPayParams().getDevice());

            paramMap.set("subject",  payOrderReqVO.getPayParams().getSubject());
            paramMap.set("body",  payOrderReqVO.getPayParams().getBody());
            // 回调URL
            paramMap.set("notifyUrl", payNotifyUrl.replace("payNotify", "bcPayNotify"));

            //扩展参数1
            paramMap.set("param1", tradeOrderPayDO.getPaymentType());
            //扩展参数2
            paramMap.set("param2", payOrderReqVO.getPayParams().getParam());
            //过期时间
            paramMap.set("expireTime", "1800");
            if( payOrderReqVO.getPayParams().getExtra() == null){
                payOrderReqVO.getPayParams().setExtra(new JSONObject());
            }
            JSONObject extra = payOrderReqVO.getPayParams().getExtra();
            extra.set("openId", tradeOrderPayDO.getOpenId());
            //ALIPAY_WAP需要的参数
            extra.set("productId", payOrderReqVO.getPayParams().getProductId());
            extra.set("tradeChannel", payOrderReqVO.getPayParams().getTradeChannel());
            extra.set("tranCode", payOrderReqVO.getPayParams().getTranCode());

            extra.set("appId", payOrderReqVO.getPayParams().getAppId());

            // 附加参数 经纬度信息也在extra参数中
            paramMap.set("extra", extra);
            String reqSign = PayDigestUtil.getSign(paramMap, tradeMchInfoDO.getReqKey());
            // 签名
            paramMap.set("sign", reqSign);
            String reqJsonStr = paramMap.toString();
            String reqDataEncode = "params=" + URLEncoder.encode(reqJsonStr, "UTF-8");
            String reqData = "params=" +reqJsonStr;
            log.info("请求支付中心下单接口,请求数据:{}", reqData);
            String url = baseUrl + "/pay/create_order?";
            String result = PayUtil.call4Post(url + reqDataEncode);
            log.info("请求支付中心下单接口（{}{}）,响应数据:{}", url, reqDataEncode, result);
            Map<String, Object> retMap = JSONUtil.parseObj(result);
            if (StrUtil.equals(SUCCESS, MapUtils.getString(retMap, "retCode"))) {
                // 补充参数
                paramMap.set("payOrderId", MapUtils.getString(retMap, "payOrderId"));
                if (retMap.containsKey("payOrder")) {
                    Object payOrderStr = retMap.get("payOrder");
                    JSONObject payOrder = JSONUtil.parseObj(payOrderStr);
                    if (!payOrder.isEmpty()) {
                        retMap.put("payOrder", paramMap);
                    }
                }
                //非银联支付返回的支付二维码
                if (retMap.get("payUrl") == null && retMap.get("codeUrl") != null) {
                    retMap.put("payUrl", retMap.get("codeUrl"));
                }
                retMap.put("channelId", paramMap.getStr("channelId"));
            }
            retMap.put("mainMid", customMchId);
            retMap.put("channelId", paramMap.getStr("channelId"));
            return JSONUtil.parseObj(retMap);
        } catch (ServiceException ex) {
            throw ex;
        } catch (Exception ex) {
            log.error("调用支付平台异常",ex);
            throw exception(PAY_PLAT_UNKNOWN_EXCEPTION);
        }
    }

    @Override
    public JSONObject createRefundOrder(RefundRecordDO refundRecordDO, RefundDO refundDO, TradeOrderPayDO tradeOrderPayDO, TradeMchInfoDO tradeMchInfoDO) {
        try {
            JSONObject paramMap = new JSONObject();
            PayOrderReqVO.PayParams payParams = new PayOrderReqVO.PayParams();
            if(StrUtil.isNotBlank(tradeOrderPayDO.getReqParams())){
                payParams = JSONUtil.toBean(tradeOrderPayDO.getReqParams(), PayOrderReqVO.PayParams.class);
            }
            boolean divisionFlag = false;
            String customMchId = refundRecordDO.getMerchantNo();
            // 商户ID
            paramMap.set("mchId", customMchId);
            // 商户退单号
            paramMap.set("mchRefundNo", refundRecordDO.getId());
            //银联支付方式
            paramMap.set("channelId", refundRecordDO.getChannelId());
            // 退款金额
            paramMap.set("amount", refundRecordDO.getRefundAmount().multiply(BigDecimal.valueOf(100)).intValue());
            // 币种, cny-人民币
            paramMap.set("currency", "cny");
            // 用户地址,微信H5支付时要真实的
            paramMap.set("clientIp", payParams.getClientIp());
            // 设备
            paramMap.set("device", payParams.getDevice());
            paramMap.set("subject", "");
            paramMap.set("body", payParams.getBody());
            // 回调URL
            paramMap.set("notifyUrl", refundNotifyUrl);
            // 扩展参数1
            paramMap.set("param1", "");
            // 扩展参数2
            paramMap.set("param2", refundRecordDO.getParam2());
            //景区及商品
            paramMap.set("param3", refundRecordDO.getParam3());
            paramMap.set("param4", payParams.getBody());
            paramMap.set("msgType", payParams.getMsgType());
            if(StrUtil.isNotBlank(refundRecordDO.getOpenId())){
                paramMap.set("channelUser", refundRecordDO.getOpenId());
            }else if(refundDO!=null && StrUtil.isNotBlank(refundDO.getCreator())){
                paramMap.set("channelUser", refundDO.getCreator());
            }else {
                paramMap.set("channelUser", tradeOrderPayDO.getCreator());
            }

            // 支付订单号
            paramMap.set("payOrderId", refundRecordDO.getPaymentNo());
            // 商户支付单号
            if(refundRecordDO.getRealPayOrderId() != null){
                paramMap.set("mchOrderNo", refundRecordDO.getRealPayOrderId());
            }else {
                paramMap.set("mchOrderNo", refundRecordDO.getOrderPayId());
            }

            paramMap.set("divisionFlag", divisionFlag);
            paramMap.set("platformAmount", refundRecordDO.getRefundAmount().multiply(BigDecimal.valueOf(100)).intValue());
            // 签名
            String reqSign = PayDigestUtil.getSign(paramMap, tradeMchInfoDO.getReqKey());
            log.info(paramMap.toString());
            paramMap.set("sign", reqSign);
            String reqData = "params=" + paramMap;
            log.info("请求支付中心退款接口,请求数据:{}", reqData);
            String url = baseUrl + "/refund/create_order?";
            String result = PayUtil.call4Post(url + reqData);
            log.info("请求支付中心退款接口,响应数据:{}", result);
            return JSONUtil.parseObj(result);

        } catch (ServiceException ex) {
            throw ex;
        } catch (Exception ex) {
            log.error("调用支付平台异常",ex);
            throw exception(PAY_PLAT_UNKNOWN_EXCEPTION);
        }
    }

    @Override
    public JSONObject payOrderQuery(TradeOrderPayDO tradeOrderPayDO, TradeMchInfoDO tradeMchInfoDO) {
        try {
            String customMchId =tradeOrderPayDO.getMerchantNo();
            JSONObject paramMap = new JSONObject();
            // 商户ID
            paramMap.set("mchId", customMchId);
            // 商户退单号
            paramMap.set("mchOrderNo", tradeOrderPayDO.getId());
            //银联支付方式
            paramMap.set("channelId", "");
            //支付订单号
            paramMap.set("payOrderId", "");
            String reqSign = PayDigestUtil.getSign(paramMap, tradeMchInfoDO.getReqKey());
            // 签名
            paramMap.set("sign", reqSign);
            String reqDataEncode = null;
            try {
                reqDataEncode = "params=" + URLEncoder.encode(paramMap.toString(), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                log.error("urlencoded 失败", e);
            }
            String reqData = "params=" + paramMap;
            log.info("请求支付中心下单反查接口,请求数据:{}", reqData);
            String url = baseUrl + "/query/create?";
            String result = PayUtil.call4Post(url + reqDataEncode);
            log.info("请求支付中心下单反查接口（{}{}）,响应数据:{}", url, reqDataEncode, result);
            return JSONUtil.parseObj(result);
        } catch (ServiceException ex) {
            throw ex;
        } catch (Exception ex) {
            log.error("调用支付平台异常",ex);
            throw exception(PAY_PLAT_UNKNOWN_EXCEPTION);
        }
    }

    @Override
    public JSONObject refundQuery(RefundRecordDO refundRecordDO, TradeMchInfoDO tradeMchInfoDO) {
        try {
            JSONObject paramMap = new JSONObject();
            String customMchId = refundRecordDO.getMerchantNo();
            // 商户ID
            paramMap.set("mchId", customMchId);
            // 商户退单号
            paramMap.set("refundOrderId", refundRecordDO.getRefundNo());
            //银联支付方式
            paramMap.set("channelId", refundRecordDO.getChannelId());
            String reqSign = PayDigestUtil.getSign(paramMap, tradeMchInfoDO.getReqKey());
            // 签名
            paramMap.set("sign", reqSign);
            String reqDataEncode = null;
            try {
                reqDataEncode = "params=" + URLEncoder.encode(paramMap.toString(), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                log.error("urlencoded 失败", e);
            }
            String reqData = "params=" + paramMap;
            log.info("请求支付中心退款反查接口,请求数据:{}", reqData);
            String url = baseUrl + "/query/refund?";
            String result = PayUtil.call4Post(url + reqDataEncode);
            log.info("请求支付中心退款反查接口（{}{}）,响应数据:{}", url, reqDataEncode, result);
            return JSONUtil.parseObj(result);
        } catch (ServiceException ex) {
            throw ex;
        } catch (Exception ex) {
            log.error("调用支付平台异常",ex);
            throw exception(PAY_PLAT_UNKNOWN_EXCEPTION);
        }
    }
}
