
package com.wteam.framework.modules.pay.serviceimpl;


import cn.hutool.json.JSONUtil;
import com.egzosn.pay.common.bean.*;
import com.egzosn.pay.web.support.HttpRequestNoticeParams;
import com.egzosn.pay.wx.v3.api.WxPayConfigStorage;
import com.egzosn.pay.wx.v3.api.WxPayService;
import com.egzosn.pay.wx.v3.bean.WxTransactionType;
import com.wteam.framework.common.enums.ResultCode;
import com.wteam.framework.common.enums.ResultUtil;
import com.wteam.framework.common.exception.ServiceException;
import com.wteam.framework.common.utils.SpringContextUtil;
import com.wteam.framework.common.vo.ResultMessage;

import com.wteam.framework.modules.book.entity.OrderInfo;
import com.wteam.framework.modules.book.service.OrderInfoService;
import com.wteam.framework.modules.pay.entity.dto.PayParam;
import com.wteam.framework.modules.pay.entity.enums.PaymentMethodEnum;
import com.wteam.framework.modules.pay.interceptor.WxV3PayMessageInterceptor;
import com.wteam.framework.modules.pay.service.Payment;
import com.wteam.framework.modules.pay.serviceimpl.handler.MyPayMessageHandler;
import com.wteam.framework.modules.pay.serviceimpl.handler.WxV3PayMessageHandler;
import com.wteam.framework.modules.system.entity.dos.Setting;
import com.wteam.framework.modules.system.entity.dto.WechatPaymentSetting;
import com.wteam.framework.modules.system.entity.enums.SettingEnum;
import com.wteam.framework.modules.system.service.SettingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

/**
 * 微信V3发起支付入口
 *
 * @author egan
 * email egzosn@gmail.com
 * date 2016/11/18 0:25
 */
@Slf4j
@Component
public class WxV3PayPlugin implements Payment {

    private WxPayService service = null;

    @Autowired
    private CashierSupport cashierSupport;
    @Autowired
    private MyPayMessageHandler myPayMessageHandler;
    @Autowired
    private OrderInfoService orderInfoService;


    /**
     * 获取微信支付配置
     *
     * @return
     */
    private static WechatPaymentSetting wechatPaymentSetting() {
        try {
            SettingService settingService = SpringContextUtil.getBean(SettingService.class);
            Setting setting = settingService.get(SettingEnum.WECHAT_PAYMENT.name());
            WechatPaymentSetting wechatPaymentSetting = JSONUtil.toBean(setting.getSettingValue(), WechatPaymentSetting.class);
            return wechatPaymentSetting;
        } catch (Exception e) {
            log.error("微信支付暂不支持", e);
            throw new ServiceException(ResultCode.PAY_NOT_SUPPORT);
        }
    }

//    @PostConstruct
    // 没有证书的情况下注释掉，避免启动报错
    public void init() {
        WechatPaymentSetting wechatPaymentSetting = wechatPaymentSetting();
        WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage();
        wxPayConfigStorage.setAppId(wechatPaymentSetting.getAppId());
        wxPayConfigStorage.setMchId(wechatPaymentSetting.getMchId());
//        V3密钥 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_2.shtml
        wxPayConfigStorage.setV3ApiKey(wechatPaymentSetting.getApiKey3());
        wxPayConfigStorage.setNotifyUrl("http://139.9.38.185:8889/v1/payment/callback/WECHAT");
        wxPayConfigStorage.setReturnUrl("http://sailinmu.iok.la/wxV3/payBack.json");
        wxPayConfigStorage.setInputCharset("utf-8");
        // 使用证书时设置为true
        wxPayConfigStorage.setCertSign(true);
        // 商户API证书 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_1.shtml
        wxPayConfigStorage.setApiClientKeyP12(wechatPaymentSetting.getApiclient_cert_p12());
        wxPayConfigStorage.setCertStoreType(CertStoreType.PATH);
        service = new WxPayService(wxPayConfigStorage);
        // 微信海外支付：东南亚
//        service.setApiServerUrl("https://apihk.mch.weixin.qq.com");
        // 增加支付回调消息拦截器
        service.addPayMessageInterceptor(new WxV3PayMessageInterceptor());
        // 设置回调消息处理
        // TODO {@link com.egzosn.pay.demo.controller.WxPayController#payBack}
        service.setPayMessageHandler(new WxV3PayMessageHandler());
//        service.setApiServerUrl("https://api.mch.weixin.qq.com");
    }


    /**
     * 小程序调起支付
     *
     * @param request HttpServletRequest
     * @param sn      支付订单号
     * @return 二维码内容
     */
    @Override
    public ResultMessage<Object> jsapiPay(HttpServletRequest request, String sn, PaymentMethodEnum paymentMethodEnum) {
        PayOrder order = cashierSupport.cashierParam(sn, paymentMethodEnum);
        order.setTransactionType(WxTransactionType.JSAPI);
        Map orderInfo = service.orderInfo(order);
        orderInfo.put("code", 0);
        return ResultUtil.data(orderInfo);
    }

    @Override
    public RefundResult refund(PaymentMethodEnum paymentMethodEnum, HttpServletRequest request, String sn) {
        //获得要退款订单信息
        OrderInfo orderInfo = orderInfoService.query().eq("id", sn).one();
        log.info("此时的订单信息为：{}", orderInfo);
        // 获得订单价格
        Double orderPrice = orderInfo.getOrderPrice();
        log.info("此时的订单价格为：{}", orderPrice);

        // 构造退款订单号，可以使用当前时间戳作为一部分，以确保唯一性
        long timestamp = System.currentTimeMillis();
        String refundOrderNumber = "REFUND_" + sn + "_" + timestamp;
        log.info("此时的生成的退款订单号为：{}", refundOrderNumber);

        // 创建一个RefundOrder对象，并设置退款金额和退款订单号
        RefundOrder refundOrder = new RefundOrder();
        refundOrder.setRefundAmount(BigDecimal.valueOf(orderPrice));
        refundOrder.setRefundNo(refundOrderNumber);
        refundOrder.setOrderDate(new Date());
        refundOrder.setUserId(orderInfo.getUserId());


        // 调用支付服务的退款方法，返回退款结果
        return service.refund(refundOrder);
    }


    /**
     * 支付回调地址
     *
     * @param request 请求
     * @return 是否成功
     * <p>
     * 业务处理在对应的PayMessageHandler里面处理，在哪里设置PayMessageHandler，详情查看{@link com.egzosn.pay.common.api.PayService#setPayMessageHandler(com.egzosn.pay.common.api.PayMessageHandler)}
     * <p>
     * 如果未设置 {@link com.egzosn.pay.common.api.PayMessageHandler} 那么会使用默认的 {@link com.egzosn.pay.common.api.DefaultPayMessageHandler}
     * @throws IOException IOException
     */
    @Override
    public String callBack(HttpServletRequest request) {
        log.info("支付异步回调：");
        // 业务处理在对应的PayMessageHandler里面处理，在哪里设置PayMessageHandler，详情查看com.egzosn.pay.common.api.PayService.setPayMessageHandler()
        service.setPayMessageHandler(myPayMessageHandler);
        return service.payBack(new HttpRequestNoticeParams(request)).toMessage();
    }


//    /**
//     * 支付回调地址
//     *
//     * @param request 请求
//     * @return 是否成功
//     * <p>
//     * 业务处理在对应的PayMessageHandler里面处理，在哪里设置PayMessageHandler，详情查看{@link com.egzosn.pay.common.api.PayService#setPayMessageHandler(com.egzosn.pay.common.api.PayMessageHandler)}
//     * <p>
//     * 如果未设置 {@link com.egzosn.pay.common.api.PayMessageHandler} 那么会使用默认的 {@link com.egzosn.pay.common.api.DefaultPayMessageHandler}
//     * @throws IOException IOException
//     */
//    public String payBack(HttpServletRequest request) {
//        //业务处理在对应的PayMessageHandler里面处理，在哪里设置PayMessageHandler，详情查看com.egzosn.pay.common.api.PayService.setPayMessageHandler()
//        return service.payBack(new HttpRequestNoticeParams(request)).toMessage();
//    }


    /**
     * 查询
     *
     * @param payParam 订单的请求体
     * @return 返回查询回来的结果集，支付方原值返回
     */
    @Override
    public Map<String, Object> query(PayParam payParam) {
        return service.query(new AssistOrder(null, payParam.getSn()));
    }

//
//    /**
//     * 交易关闭接口
//     *
//     * @param order 订单的请求体
//     * @return 返回支付方交易关闭后的结果
//     */
//    @RequestMapping("close")
//    public Map<String, Object> close(QueryOrder order) {
//        return service.close(new AssistOrder(order.getTradeNo(), order.getOutTradeNo()));
//    }

    /**
     * 申请退款接口
     *
     * @param order 订单的请求体
     * @return 返回支付方申请退款后的结果
     */
    @RequestMapping("refund")
    public RefundResult refund(RefundOrder order) {
        return service.refund(order);
    }


    /**
     * 查询退款
     *
     * @param order 订单的请求体
     * @return 返回支付方查询退款后的结果
     */
    @RequestMapping("refundquery")
    public Map<String, Object> refundquery(RefundOrder order) {
        return service.refundquery(order);
    }

//    /**
//     * 下载对账单
//     *
//     * @param order 订单的请求体
//     * @return 返回支付方下载对账单的结果
//     */
//    @RequestMapping("downloadbill")
//    public Object downloadBill(QueryOrder order) {
//        return service.downloadBill(order.getBillDate(), order.getBillType());
//    }
//
//    /**
//     * 转账到余额
//     *
//     *
//     * @return 对应的转账结果
//     */
//    @RequestMapping("transfer")
//    public Map<String, Object> transfer() {
//
//        WxTransferOrder order = new WxTransferOrder();
//        order.setOutBatchNo("商户系统内部的商家批次单号，要求此参数只能由数字、大小写字母组成，在商户系统内部唯一");
//        order.setBatchName("该笔批量转账的名称");
//        order.setBatchRemark("转账说明，UTF8编码，最多允许32个字符");
//        // 转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致，否则无法发起转账操作
//        order.setTotalAmount(100);
//        //一个转账批次单最多发起一千笔转账。转账总笔数必须与批次内所有明细之和保持一致，否则无法发起转账操作
//        order.setTotalNum(1);
//        TransferDetail transferDetail = new TransferDetail();
//        transferDetail.setOutDetailNo("商户系统内部区分转账批次单下不同转账明细单的唯一标识，要求此参数只能由数字、大小写字母组成");
//        // 转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致，否则无法发起转账操作
//        transferDetail.setTransferAmount(100);
//        transferDetail.setTransferRemark("单条转账备注（微信用户会收到该备注），UTF8编码，最多允许32个字符");
//        transferDetail.setOpenid("商户appid下，某用户的openid");
//        transferDetail.setUserName("收款方真实姓名: 张三");
//        transferDetail.setUserIdCard("当填入收款方身份证号时，姓名字段必须填入。");
//        order.setTransferDetailList(Collections.singletonList(transferDetail));
//        //发起商家转账,转账到零钱
//        order.setTransferType(WxTransferType.TRANSFER_BATCHES);
//        order.setTransferSceneId("必填，指定该笔转账使用的转账场景ID");
//        return service.transfer(order);
//    }
//    /**
//     * 转账账单电子回单申请受理接口
//     *
//     *
//     * @return 转账账单电子回单申请受理接口结果
//     */
//    @RequestMapping("billReceipt")
//    public Map<String, Object> billReceipt() {
//        WxTransferOrder order = new WxTransferOrder();
//        order.setOutBatchNo("商户系统内部的商家批次单号，要求此参数只能由数字、大小写字母组成，在商户系统内部唯一");
//        //转账账单电子回单申请受理接口
//        order.setTransferType(WxTransferType.TRANSFER_BILL_RECEIPT);
//        return service.transfer(order);
//    }
//
//
//    /**
//     * 通过微信批次单号查询批次单
//     *
//     * <p>
//     *  <a href="https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-batch/get-transfer-batch-by-no.html">通过微信批次单号查询批次单</a>
//     * </p>
//     * @return 对应的转账订单
//     */
//    @RequestMapping("getTransferBatchByNo")
//    public Map<String, Object> getTransferBatchByNo() {
//        WxTransferQueryOrder queryOrder = new WxTransferQueryOrder();
//        queryOrder.setBatchId("1030000071100999991182020050700019480001");
//        queryOrder.setNeedQueryDetail(true);
//        queryOrder.setOffset(0);
//        queryOrder.setLimit(20);
//        queryOrder.setDetailStatus("FAIL");
//        queryOrder.setTransactionType(WxTransferType.QUERY_BATCH_BY_BATCH_ID);
//        return service.transferQuery(queryOrder);
//    }
//    /**
//     * 通过微信批次单号查询批次单
//     *
//     * <p>
//     *  <a href="https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-batch/get-transfer-batch-by-out-no.html">通过商家批次单号查询批次单</a>
//     * </p>
//     * @return 对应的转账订单
//     */
//    @RequestMapping("getTransferBatchByOutNo")
//    public Map<String, Object> getTransferBatchByOutNo() {
//        WxTransferQueryOrder queryOrder = new WxTransferQueryOrder();
//        queryOrder.setOutBatchNo("1030000071100999991182020050700019480001");
//        queryOrder.setNeedQueryDetail(true);
//        queryOrder.setOffset(0);
//        queryOrder.setLimit(20);
//        queryOrder.setDetailStatus("FAIL");
//        queryOrder.setTransactionType(WxTransferType.QUERY_BATCH_BY_OUT_BATCH_NO);
//        return service.transferQuery(queryOrder);
//    }
//    /**
//     * 通过微信明细单号查询明细单
//     *
//     * <p>
//     *  <a href="https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-detail/get-transfer-detail-by-no.html">通过微信明细单号查询明细单</a>
//     * </p>
//     * @return 对应的转账订单
//     */
//    @RequestMapping("getTransferDetailByNo")
//    public Map<String, Object> getTransferDetailByNo() {
//        WxTransferQueryOrder queryOrder = new WxTransferQueryOrder();
//        queryOrder.setBatchId("1030000071100999991182020050700019480001");
//        queryOrder.setDetailId("1040000071100999991182020050700019500100");
//        queryOrder.setTransactionType(WxTransferType.QUERY_BATCH_DETAIL_BY_BATCH_ID);
//        return service.transferQuery(queryOrder);
//    }
//    /**
//     * 通过商家明细单号查询明细单
//     *
//     * <p>
//     *  <a href="https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-detail/get-transfer-detail-by-out-no.html">通过商家明细单号查询明细单</a>
//     * </p>
//     * @return 对应的转账订单
//     */
//    @RequestMapping("getTransferDetailByOutNo")
//    public Map<String, Object> getTransferDetailByOutNo() {
//        WxTransferQueryOrder queryOrder = new WxTransferQueryOrder();
//        queryOrder.setOutDetailNo("x23zy545Bd5436");
//        queryOrder.setOutBatchNo("plfk2020042013");
//        queryOrder.setTransactionType(WxTransferType.QUERY_BATCH_DETAIL_BY_OUT_BATCH_NO);
//        return service.transferQuery(queryOrder);
//    }
//    /**
//     * 查询转账账单电子回单接口
//     *
//     * <p>
//     *  <a href="https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-detail/get-transfer-detail-by-out-no.html">查询转账账单电子回单接口</a>
//     * </p>
//     * @return 对应的转账订单
//     */
//    @RequestMapping("getElectronicSignatureByOutNo")
//    public Map<String, Object> getElectronicSignatureByOutNo() {
//        WxTransferQueryOrder queryOrder = new WxTransferQueryOrder();
//        queryOrder.setOutBatchNo("plfk2020042013");
//        queryOrder.setTransactionType(WxTransferType.QUERY_TRANSFER_BILL_RECEIPT);
//        return service.transferQuery(queryOrder);
//    }

}
