package com.yonge.toolset.payment.adapay;

import com.alibaba.fastjson.JSONObject;
import com.huifu.adapay.core.AdapayCore;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.core.util.AdapaySign;
import com.huifu.adapay.model.Refund;
import com.yonge.toolset.base.result.BaseResult;
import com.yonge.toolset.base.util.StringUtil;
import com.yonge.toolset.payment.adapay.constant.AdapayConstant;
import com.yonge.toolset.payment.base.PaymentTemplate;
import com.yonge.toolset.payment.base.enums.*;
import com.yonge.toolset.payment.base.model.ClosePayment;
import com.yonge.toolset.payment.base.model.OpenAuth;
import com.yonge.toolset.payment.base.model.Payment;
import com.yonge.toolset.payment.base.model.RefundBill;
import com.yonge.toolset.payment.base.model.callback.ClosePaymentCallBack;
import com.yonge.toolset.payment.base.model.callback.ExecutePaymentCallBack;
import com.yonge.toolset.payment.base.model.callback.PaymentCallBack;
import com.yonge.toolset.payment.base.model.callback.RefundPaymentCallBack;
import com.yonge.toolset.payment.core.props.PaymentProperties;
import com.yonge.toolset.payment.core.service.SysConfigPaymentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class AdapayTemplate implements PaymentTemplate {
    private final static Logger log = LoggerFactory.getLogger(AdapayTemplate.class);

    @Autowired
    private PaymentProperties paymentProperties;

    @Autowired
    private SysConfigPaymentService configPaymentService;

    @Override
    public BaseResult<Map<String, Object>> getOpenAuthMsg(OpenAuth openAuth) {
        return null;
    }

    @Override
    public BaseResult<Payment> executePayment(Payment payment) {
        Map<String, Object> paymentMap = new HashMap<>();
        paymentMap.put("order_no", payment.getPaymentNo());
        paymentMap.put("app_id", configPaymentService.getPaymentConfig(payment.getOpenType(), AdapayConstant.APP_ID).getParamValue());
        paymentMap.put("pay_channel", payment.getPayChannel().getCode());
        paymentMap.put("pay_amt", payment.getPayAmt());
        paymentMap.put("goods_title", payment.getOrderTitle());
        paymentMap.put("goods_desc", payment.getOrderDesc());
        paymentMap.put("div_members", JSONObject.toJSONString(payment.getDivMembers()));
        paymentMap.put("description", payment.getDescription());
        paymentMap.put("device_info", payment.getDeviceInfo());
        paymentMap.put("expend", payment.getExpend());
        paymentMap.put("notify_url", paymentProperties.getNotifyUrl()
                + "/" + payment.getOpenType().getCode()
                + "/" + payment.getPayChannel().getCode()
                + "/executePayment"
        );
        //调用sdk方法，创建支付，得到支付对象
        Map<String, Object> res;
        try {
            res = com.huifu.adapay.model.Payment.create(paymentMap);
        } catch (BaseAdaPayException e) {
            return BaseResult.failed(e.getMessage());
        }
        if (CollectionUtils.isEmpty(res)) {
            return BaseResult.failed("请求失败");
        }
        log.info("汇付[创建支付对象] Resp：{}", res);
        String errorCode = (String) res.get("error_code");
        if (null != errorCode) {
            String errorMsg = (String) res.get("error_msg");
            return BaseResult.failed(errorMsg);
        }
        payment.setId(res.get("id").toString());
        payment.setStatus(TradeStatusEnum.getByName(res.get("status").toString()));

        String pay_info = ((JSONObject) res.get("expend")).getString("pay_info");
        payment.setPayInfo(pay_info);
        return BaseResult.succeed(payment);
    }

    @Override
    public BaseResult<Payment> queryPayment(Payment payment) {
        try {
            Map<String, Object> resMap = com.huifu.adapay.model.Payment.query(payment.getId());
            String error_code = StringUtil.get(resMap.get("error_code"));
            if (null != error_code) {
                String error_msg = StringUtil.get(resMap.get("error_msg"));
                return BaseResult.failed(error_msg);
            }
            payment.setStatus(TradeStatusEnum.getByName(StringUtil.get(resMap.get("status"))));
            payment.setPaymentNo(StringUtil.get(resMap.get("order_no")));
            payment.setPayAmt(StringUtil.get(resMap.get("pay_amt")));
            payment.setPayChannel(PayChannelEnum.valueOf(StringUtil.get(resMap.get("status"))));
            return BaseResult.succeed(payment);
        } catch (BaseAdaPayException e) {
            e.printStackTrace();
            return BaseResult.failed("支付订单查询异常");
        }
    }

    @Override
    public BaseResult<ClosePayment> closePayment(ClosePayment closePayment) {
        if(StringUtil.isEmpty(closePayment.getId())){
            return BaseResult.failed("缺失渠道关单必要参数");
        }

        Map<String, Object> paymentParams = new HashMap<>(10);
        paymentParams.put("payment_id", closePayment.getId());
        paymentParams.put("reason", closePayment.getReason());
        paymentParams.put("expend", closePayment.getExpend());
        paymentParams.put("notify_url", paymentProperties.getNotifyUrl()
                + "/" + closePayment.getOpenType().getCode()
                + "/" + closePayment.getPayChannel().getCode()
                + "/closePayment"
        );
        Map<String, Object> res;
        try {
            res = com.huifu.adapay.model.Payment.close(paymentParams);
        } catch (BaseAdaPayException e) {
            return BaseResult.failed(e.getMessage());
        }
        if (CollectionUtils.isEmpty(res)) {
            return BaseResult.failed("请求失败");
        }
        log.info("汇付[支付关单] Resp：{}", res);
        String errorCode = (String) res.get("error_code");
        if (null != errorCode) {
            String errorMsg = (String) res.get("error_msg");
            return BaseResult.failed(errorMsg);
        }
        closePayment.setStatus(TradeStatusEnum.succeeded);
        return BaseResult.succeed(closePayment);
    }

    @Override
    public BaseResult<RefundBill> refundPayment(RefundBill refundBill) {
        Map<String, Object> refundParams = new HashMap<>(10);
        refundParams.put("refund_amt", refundBill.getRefundAmt());
        refundParams.put("refund_order_no", refundBill.getRefundNo());
        refundParams.put("notify_url", paymentProperties.getNotifyUrl()
                + "/" + refundBill.getOpenType().getCode()
                + "/" + refundBill.getPayChannel().getCode()
                + "/refundPayment"
        );
        Map<String, Object> res;
        try {
            res = Refund.create(refundBill.getId(), refundParams);
        } catch (BaseAdaPayException e) {
            return BaseResult.failed(e.getMessage());
        }
        if (CollectionUtils.isEmpty(res)) {
            return BaseResult.failed("请求失败");
        }
        log.info("汇付[支付退款] Resp：{}", res);
        String errorCode = (String) res.get("error_code");
        if (null != errorCode) {
            String errorMsg = (String) res.get("error_msg");
            return BaseResult.failed(errorMsg);
        }
        refundBill.setId(res.get("id").toString());
        refundBill.setStatus(TradeStatusEnum.getByName(res.get("status").toString()));
        return BaseResult.succeed(refundBill);
    }

    @Override
    public BaseResult<PaymentCallBack> analysisNotice(OpenEnum openType, PaymentClientEnum paymentClient, PayChannelEnum payChannel, MethodNameEnum methodName, HttpServletRequest request) {
        PaymentCallBack paymentCallBack = new PaymentCallBack();
        try {
            //验签传参data
            String data = request.getParameter("data");
            //验签传参sign
            String sign = request.getParameter("sign");
            //回调业务类型
            String type = request.getParameter("type");
            log.info("汇付回调，type is {},sign is {}, data is {}", type, sign, data);
            if (com.huifu.adapay.core.util.StringUtil.isEmpty(type)) {
                log.error("汇付回调参数异常");
                return null;
            }
            //验签传参publicKey
            String publicKey = AdapayCore.PUBLIC_KEY;
            //验签
            boolean checkSign = AdapaySign.verifySign(data, sign, publicKey);
            if (checkSign) {
                JSONObject hfRes = JSONObject.parseObject(data);

                if (type.equals("payment.succeeded")) {//支付成功
                    paymentCallBack.setId(hfRes.getString("id"));
                    paymentCallBack.setPaymentNo(hfRes.getString("order_no"));
                    paymentCallBack.setStatus(TradeStatusEnum.succeeded);
                    paymentCallBack.setMethodName(MethodNameEnum.executePayment);

                    ExecutePaymentCallBack executePayment = new ExecutePaymentCallBack();
                    executePayment.setPayAmt(hfRes.getString("pay_amt"));
                    executePayment.setFeeAmt(hfRes.getString("fee_amt"));

                    if(!StringUtil.isEmpty(hfRes.getString("created_time"))){
                        executePayment.setTradeTime(new Date(Long.parseLong(hfRes.getString("created_time"))));
                    }
                    paymentCallBack.setExecutePaymentCallBack(executePayment);
                } else if (type.equals("payment.failed")) {//支付失败
                    paymentCallBack.setId(hfRes.getString("id"));
                    paymentCallBack.setPaymentNo(hfRes.getString("order_no"));
                    paymentCallBack.setStatus(TradeStatusEnum.failed);
                    paymentCallBack.setMethodName(MethodNameEnum.executePayment);

                    ExecutePaymentCallBack executePayment = new ExecutePaymentCallBack();
                    executePayment.setPayAmt(hfRes.getString("pay_amt"));
                    if(!StringUtil.isEmpty(hfRes.getString("created_time"))){
                        executePayment.setTradeTime(new Date(Long.parseLong(hfRes.getString("created_time"))));
                    }
                    paymentCallBack.setExecutePaymentCallBack(executePayment);
                } else if (type.equals("payment.close.succeeded")) {//支付关单成功
                    paymentCallBack.setId(hfRes.getString("payment_id"));
                    paymentCallBack.setStatus(TradeStatusEnum.succeeded);
                    paymentCallBack.setMethodName(MethodNameEnum.closePayment);

                    ClosePaymentCallBack closePayment = new ClosePaymentCallBack();
                    if(!StringUtil.isEmpty(hfRes.getString("created_time"))){
                        closePayment.setTradeTime(new Date(Long.parseLong(hfRes.getString("created_time"))));
                    }
                    paymentCallBack.setClosePaymentCallBack(closePayment);
                } else if (type.equals("payment.close.failed")) {//支付关单失败
                    paymentCallBack.setId(hfRes.getString("payment_id"));
                    paymentCallBack.setStatus(TradeStatusEnum.failed);
                    paymentCallBack.setErrMsg(hfRes.getString("error_msg"));
                    paymentCallBack.setMethodName(MethodNameEnum.closePayment);

                    ClosePaymentCallBack closePayment = new ClosePaymentCallBack();
                    if(!StringUtil.isEmpty(hfRes.getString("created_time"))){
                        closePayment.setTradeTime(new Date(Long.parseLong(hfRes.getString("created_time"))));
                    }
                    paymentCallBack.setClosePaymentCallBack(closePayment);
                } else if (type.equals("refund.succeeded")) {//退款成功
                    paymentCallBack.setId(hfRes.getString("payment_id"));
                    paymentCallBack.setStatus(TradeStatusEnum.succeeded);
                    paymentCallBack.setMethodName(MethodNameEnum.refundPayment);

                    RefundPaymentCallBack refundPayment = new RefundPaymentCallBack();
                    refundPayment.setBillNo(hfRes.getString("refund_order_no"));
                    refundPayment.setTransNo(hfRes.getString("id"));
                    refundPayment.setRefundAmt(hfRes.getString("pay_amt"));
                    refundPayment.setFeeAmt(hfRes.getString("fee_amt"));
                    if(!StringUtil.isEmpty(hfRes.getString("created_time"))){
                        refundPayment.setTradeTime(new Date(Long.parseLong(hfRes.getString("created_time"))));
                    }
                    paymentCallBack.setRefundPaymentCallBack(refundPayment);
                } else if (type.equals("refund.failed")) {//退款失败
                    paymentCallBack.setId(hfRes.getString("payment_id"));
                    paymentCallBack.setStatus(TradeStatusEnum.failed);
                    paymentCallBack.setErrMsg(hfRes.getString("error_msg"));
                    paymentCallBack.setMethodName(MethodNameEnum.closePayment);

                    RefundPaymentCallBack refundPayment = new RefundPaymentCallBack();
                    refundPayment.setBillNo(hfRes.getString("refund_order_no"));
                    refundPayment.setTransNo(hfRes.getString("id"));
                    refundPayment.setRefundAmt(hfRes.getString("pay_amt"));
                    refundPayment.setFeeAmt(hfRes.getString("fee_amt"));
                    if(!StringUtil.isEmpty(hfRes.getString("created_time"))){
                        refundPayment.setTradeTime(new Date(Long.parseLong(hfRes.getString("created_time"))));
                    }
                    paymentCallBack.setRefundPaymentCallBack(refundPayment);
                }
                return BaseResult.succeed(paymentCallBack);
            } else {
                return BaseResult.failed(HttpStatus.INTERNAL_SERVER_ERROR, paymentCallBack, "未通过验签");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResult.failed(HttpStatus.INTERNAL_SERVER_ERROR, paymentCallBack, "解析异常");
        }
    }
}
