package com.ghy.common.adapay;

import com.ghy.common.adapay.callback.DrawCashCallback;
import com.ghy.common.adapay.callback.PayCallback;
import com.ghy.common.adapay.callback.RefundCallback;
import com.ghy.common.adapay.callback.mapping.DrawCashReplyMapping;
import com.ghy.common.adapay.callback.mapping.PayReplyMapping;
import com.ghy.common.adapay.callback.mapping.RefundReplyMapping;
import com.ghy.common.adapay.callback.model.Expend;
import com.ghy.common.adapay.callback.model.WxLiteExpend;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.model.Drawcash;
import com.huifu.adapay.model.Payment;
import com.huifu.adapay.model.Refund;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;

/**
 * @author HH 2022/3/25
 */
@Setter
public class AdapayService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AdapayProperties adapayProperties;

    /**
     * 对指定商户或者商户下用户的结算账户可用余额发起主动取现操作，金额从账户中提到绑定的结算银行卡中
     *
     * @param callback [必填项]处理提现结果的接口
     * @param orderNo  [必填项]请求订单号，只能为英文、数字或者下划线的一种或多种组合，保证在app_id下唯一
     * @param cashType [必填项]取现类型：T1-T+1取现；D1-D+1取现；D0-即时取现。
     * @param cashAmt  [必填项]取现金额，必须大于0，人民币为元，保留两位小数点，如"0.10"、"100.05"等
     * @param memberId [必填项]用户对象的member_id，若是商户本身取现时，请传入0
     * @param remark   备注
     * @param feeMode  手续费收取模式：O-商户手续费账户扣取手续费，I-交易金额中扣取手续费；值为空时，默认值为I；
     * @return https://docs.adapay.tech/api/wallet.html#cash-response
     */
    public Map<String, Object> drawCash(DrawCashCallback callback, String orderNo, String cashType, String cashAmt,
                                        String memberId, String remark, String feeMode) throws BaseAdaPayException {
        Assert.notNull(callback, "callback is null!");
        Assert.hasText(orderNo, "orderNo is blank!");
        Assert.hasText(cashType, "cashType is blank!");
        Assert.hasText(cashAmt, "cashAmt is blank!");
        Assert.hasText(memberId, "memberId is blank!");
        Map<String, Object> cashParam = new HashMap<>(5);
        cashParam.put("order_no", orderNo);
        cashParam.put("app_id", adapayProperties.getAppId());
        cashParam.put("cash_type", cashType);
        cashParam.put("cash_amt", cashAmt);
        cashParam.put("member_id", memberId);
        cashParam.put("notify_url", adapayProperties.getNotifyUrl());
        cashParam.put("remark", remark);
        cashParam.put("fee_mode", feeMode);
        DrawCashReplyMapping.putCallback(orderNo, callback);
        return Drawcash.create(cashParam);
    }

    /**
     * 支付宝正扫支付
     */
    public Map<String, Object> alipayQrPay(PayCallback callback, WxLiteExpend expend, String orderNo, String payAmt,
                                           String goodsTittle, String goodsDesc, String divMembers, String description) throws BaseAdaPayException {
        return pay(callback, PayChannelEnum.ALIPAY_QR.getCode(), expend, orderNo, payAmt, goodsTittle, goodsDesc, divMembers, description);
    }

    /**
     * 微信小程序支付
     */
    public Map<String, Object> wxPubPay(PayCallback callback, WxLiteExpend expend, String orderNo, String payAmt,
                                        String goodsTittle, String goodsDesc, String divMembers, String description) throws BaseAdaPayException {
        return pay(callback, PayChannelEnum.WX_PUB.getCode(), expend, orderNo, payAmt, goodsTittle, goodsDesc, divMembers, description);
    }

    /**
     * 微信小程序支付
     */
    public Map<String, Object> wxLitePay(PayCallback callback, WxLiteExpend expend, String orderNo, String payAmt,
                                         String goodsTittle, String goodsDesc, String divMembers, String description) throws BaseAdaPayException {
        return pay(callback, PayChannelEnum.WX_LITE.getCode(), expend, orderNo, payAmt, goodsTittle, goodsDesc, divMembers, description);
    }

    /**
     * @param callback    [必填项]处理支付结果的回调接口
     * @param orderNo     [必填项]订单号
     * @param payAmt      [必填项]交易金额，必须大于0，保留两位小数点，如"0.10"、"100.05"
     * @param goodsTittle [必填项]商品名称
     * @param goodsDesc   [必填项]商品描述信息，微信小程序和微信公众号该字段最大长度42个字符
     * @param payChannel  [必填项]支付渠道，详见 https://docs.adapay.tech/api/appendix.html#id2
     * @param expend      支付渠道额外参数，条件可输入，详见 https://docs.adapay.tech/api/appendix.html#expend
     * @param divMembers  分账对象信息列表，最多仅支持7个分账方，json 数组形式，详见 https://docs.adapay.tech/api/appendix.html#divmembers
     * @param description 订单附加说明
     * @return 同步返回一个 支付对象，详见 https://docs.adapay.tech/api/trade.html#id2
     */
    public Map<String, Object> pay(PayCallback callback, String payChannel, Expend expend, String orderNo, String payAmt,
                                   String goodsTittle, String goodsDesc, String divMembers, String description) throws BaseAdaPayException {
        Map<String, Object> paymentParams = new HashMap<>(16);
        paymentParams.put("app_id", adapayProperties.getAppId());
        paymentParams.put("notify_url", adapayProperties.getNotifyUrl());
        paymentParams.put("order_no", orderNo);
        paymentParams.put("pay_channel", payChannel);
        paymentParams.put("pay_amt", payAmt);
        paymentParams.put("goods_title", goodsTittle);
        paymentParams.put("goods_desc", goodsDesc);
        paymentParams.put("div_members", divMembers);
        paymentParams.put("description", description);
        paymentParams.put("expend", expend);
        PayReplyMapping.putCallback(orderNo, callback);

        paymentParams.forEach((key, value) -> {
            logger.info("key is " + key + ", value is " + value);
        });
        return Payment.create(paymentParams);
    }

    /**
     * 发起退款
     * 当您的业务需要发起退款时，可通过 Adapay 系统提供的创建 Refund对象 方法创建一个退款对象，资金会原路退回用户的支付宝或微信中。
     * 支持一次全额或多次部分退款，退款次数最多不超过10次。多次部分退款时，当前退款金额 + 已退款金额不能大于原支付金额。
     * 对于每次撤销交易，Adapay 都会通过 异步消息通知 告知结果。
     * 退款对象同步返回成功，表示Adapay受理成功，退款结果以异步通知为准。支持退款最长时间为178天，
     * 若返回码是“order_id_not_exists 订单记录不存在”，既超过退款期限，无法退款成功。
     *
     * @param callback      [必填项]处理退款结果的回调接口
     * @param paymentId     [必填项]支付确认对象的id
     * @param refundOrderNo [必填项]订单号
     * @param refundAmt     [必填项]退款金额，若退款金额小于原交易金额，则认为是部分退款，必须大于0，保留两位小数点，如0.10、100.05等
     * @return 同步返回一个 退款对象 https://docs.adapay.tech/api/trade.html#create-refund-params
     */
    public Map<String, Object> refund(RefundCallback callback, String paymentId, String refundOrderNo, String refundAmt) throws BaseAdaPayException {
        Assert.notNull(callback, "callback is null!");
        Assert.hasText(paymentId, "paymentId is blank!");
        Assert.hasText(refundOrderNo, "refundOrderNo is blank!");
        Assert.hasText(refundAmt, "refundAmt is blank!");
        Map<String, Object> refundParams = new HashMap<>(4);
        refundParams.put("refund_amt", refundAmt);
        refundParams.put("refund_order_no", refundOrderNo);
        RefundReplyMapping.putCallback(paymentId, callback);
        return Refund.create(paymentId, refundParams);
    }

    /**
     * 支付关单
     * 针对已经创建的 支付对象，您可以调用关单接口进行交易的关闭。调用此接口后，该用户订单将不再能支付成功。 对于关单功能的使用有如下规则：
     * 1.存在关单记录，不能再次关单
     * 2.交易时间 1分钟 内无法关单成功
     * 3.正扫交易时间超过 2小时 无法关单成功
     * 4.支付宝正扫接口，如果用户没有扫码，订单不能关闭成功（二维码给用户展示，如果用户没有用手机去扫码，那这笔就不能关单； 如果用户扫过了的话（无需支付成功）就可以关单了）—-微信正扫无此条限制
     * 5.网银和快捷类交易都不支持关单操作
     *
     * @param paymentId [必填项]由 Adapay 生成的支付对象 id
     * @param reason    关单描述
     * @param expend    扩展域
     * @return 关单的结果将通过一个 JSON 同步返回 https://docs.adapay.tech/api/trade.html#close-payment-response
     */
    public Map<String, Object> close(String paymentId, String reason, String expend) throws BaseAdaPayException {
        Assert.hasText(paymentId, "paymentId is blank!");
        Map<String, Object> paymentParams = new HashMap<>(4);
        paymentParams.put("payment_id", paymentId);
        paymentParams.put("reason", reason);
        paymentParams.put("expend", expend);
        return Payment.close(paymentParams);
    }

}