package com.fzm.mall.server.front.repo.alipay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse;
import com.alipay.easysdk.payment.common.models.*;
import com.fzm.mall.server.front.asset.model.OrderPay;
import com.fzm.mall.server.front.constant.MALLGlobalConfig;
import com.fzm.mall.server.front.constant.MallResponseEnum;
import com.fzm.mall.server.front.order.service.IDeliveryService;
import com.fzm.mall.server.front.order.service.IOrderService;
import com.fzm.mall.server.front.util.UUIdUtil;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@RestController
@Slf4j
@RequestMapping("/mall/alipay")
public class AlipayController {
    @Autowired
    private Config alipayOptions;

    @Value("${alipay.return-url}")
    private String returnUrl;

    @Value("${alipay.quit-url}")
    private String quitUrl;

    @Value("${alipay.pay-notify-url}")
    private String payNotifyUrl;

    @Value("${alipay.refund-notify-url}")
    private String refundNotifyUrl;

    @Value("${alipay.pay-postfee-url}")
    private String payPostFeeUrl;

    @Autowired
    private IDeliveryService deliveryService;

    @PostConstruct
    private void initOptions() {
        Factory.setOptions(alipayOptions);
    }


    @PostMapping("/pay")
    public JSONObject pay() {
        String subject = "";
        String outTradeNo = "";
        String totalAmt = "";

        String newQuitUrl = quitUrl;
        String newReturnUrl = returnUrl + outTradeNo;

        JSONObject jsonObj = new JSONObject();
        try {
            // 单独指定回调地址
            AlipayTradeAppPayResponse res = Factory.Payment.App().asyncNotify(payNotifyUrl)
                    .optional("enable_pay_channels", "balance,moneyFund,bankPay,debitCardExpress").optional("return_url", newReturnUrl).optional("passback_params", newReturnUrl)
                    .pay(subject, outTradeNo, totalAmt);
            // AlipayTradeWapPayResponse res = Factory.Payment.Wap().pay(subject,
            // outTradeNo, totalAmt, newQuitUrl, newReturnUrl);

            log.info("收到付款请求：" + outTradeNo);
            System.out.println(res);
            if (ResponseChecker.success(res)) {
                jsonObj.put("outTradeNo", outTradeNo);
                jsonObj.put("form", res.body);
                log.error(JSON.toJSONString(jsonObj));
                return jsonObj;
            } else {
                // 撤销交易
                AlipayTradeCancelResponse res1 = Factory.Payment.Common().cancel(outTradeNo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return jsonObj;
    }

    /**
     * 回调数据文档 https://opendocs.alipay.com/open/203/105286
     */
    /*
     * @PostMapping("/mainNotify") public String mainNotify(HttpServletRequest req)
     * { log.info("收到支付宝回调通知：  "); try { Map<String, String> params =
     * genParams(req); log.info(JSON.toJSONString(params)); // 验签
     * if(Factory.Payment.Common().verifyNotify(params)){ // 该交易在支付宝系统中的交易流水号。最长64位。
     * String tradeNo = params.get("trade_no"); // 交易状态 String tradeStatus =
     * params.get("trade_status"); // 商户业务ID，主要是退款通知中返回退款申请的流水号 String outBizNo =
     * params.get("out_biz_no"); String refundFee = params.get("refund_fee");
     * AlipayTradeStautsEnum statusEnum =
     * AlipayTradeStautsEnum.getEnum(tradeStatus);
     *
     * switch (statusEnum){ case SUCCESS: // 支付成功，或部分退款 退款成功 break; case CLOSED: //
     * 未付款交易超时关闭，或支付完成后全额退款 break; case FINISHED: // 交易完结 break; case BUYER_PAY: //
     * 交易创建 break; default: break; }
     *
     *
     * // 如果商户反馈给支付宝的字符不是success这7个字符，支付宝服务器会不断重发通知，直到超过24小时22分钟。一般情况下，25小时以内完成8次通知（
     * 通知的间隔频率一般是：4m,10m,10m,1h,2h,6h,15h） return
     * XLSGlobalConfig.ALIPAY_RES_SUCCESS; } } catch (Exception e) {
     * e.printStackTrace(); } return XLSGlobalConfig.ALIPAY_RES_FAILED; }
     */

    // 支付回调
    @PostMapping("/without/payNotify")
    public String payNotify(HttpServletRequest req) {
        try {
            Map<String, String> params = genParams(req);
            log.info("收到支付宝的支付回调：");
            log.info(JSON.toJSONString(params));
            // 验签
            if (Factory.Payment.Common().verifyNotify(params)) {
                String tradeNo = params.get("trade_no");
                // 交易状态
                String tradeStatus = params.get("trade_status");
                // 商户业务ID，主要是退款通知中返回退款申请的流水号
                String outBizNo = params.get("out_biz_no");
                String refundFee = params.get("refund_fee");
                String out_trade_no = params.get("out_trade_no");
                AlipayTradeStautsEnum statusEnum = AlipayTradeStautsEnum.getEnum(tradeStatus);
                log.info(out_trade_no);
                switch (statusEnum) {
                    case SUCCESS:
                        // 支付成功，或部分退款 退款成功
                        log.info(out_trade_no + "success");
                        if (StringUtil.isNullOrEmpty(refundFee)) {

                        } else {

                        }

                        break;
                    case CLOSED:
                        log.info(out_trade_no + "closed");
                        // 未付款交易超时关闭，或支付完成后全额退款
                        if (!StringUtil.isNullOrEmpty(refundFee)) {
                            log.info(out_trade_no + "closed run");

                        }
                        break;
                    case FINISHED:
                        // 交易完结
                        log.info(out_trade_no + "finished");
                        break;
                    case BUYER_PAY:
                        // 交易创建
                        log.info(out_trade_no + "buyPay");
                        break;
                    default:
                        break;
                }
                return MALLGlobalConfig.ALIPAY_RES_SUCCESS;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return MALLGlobalConfig.ALIPAY_RES_FAILED;
    }

    @PostMapping("/refund")
    public String refund(@RequestParam String outTradeNo, @RequestParam String amount) {
        log.info("收到退款请求：" + outTradeNo + "--" + amount);
        try {
            // 可设置异步通知地址
            // String notifyUrl = "xxxx";
            // Factory.Payment.Common().asyncNotify(notifyUrl).refund(outTradeNo, amount);
            String outRequestNo = UUIdUtil.getUUID();
            AlipayTradeRefundResponse res = Factory.Payment.Common().optional("out_request_no", outRequestNo)
                    .refund(outTradeNo, amount);

            if (ResponseChecker.success(res)) {
                log.info("退款成功~");
                return "success";
            } else {
                return "error";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "error";
    }

    @PostMapping("/without/query")
    public String query(@RequestParam String outTradeNo, @RequestParam String outRequestNo) {
        try {
            // 查询交易
            AlipayTradeQueryResponse res1 = Factory.Payment.Common().query(outTradeNo);
            System.out.println(JSON.toJSONString(res1));
            // 查询退款
            AlipayTradeFastpayRefundQueryResponse res2 = Factory.Payment.Common().queryRefund(outTradeNo, outRequestNo);

            // 关闭交易
            AlipayTradeCloseResponse res3 = Factory.Payment.Common().close(outTradeNo);

            // 撤销交易
            AlipayTradeCancelResponse res4 = Factory.Payment.Common().cancel(outTradeNo);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return "success";
    }

    public JSONObject payPostFee(OrderPay payResult) {
        JSONObject jsonObj = new JSONObject();
        if (payResult.getTotal().compareTo(BigDecimal.ZERO) == 0) {
            try {
                deliveryService.paymentsPostFee(payResult.getPayId(), "", 1);
                jsonObj.put("result", "success");
                jsonObj.put("pid", payResult.getPayId());
            } catch (Exception e) {
                log.error(e.toString());
                jsonObj.put("result", "fail");
                jsonObj.put("pid", payResult.getPayId());
            }
            return jsonObj;
        }
        String subject = "快递费测试 0.01";
        String outTradeNo = payResult.getPayId();
        String totalAmt = payResult.getTotal().setScale(2).toPlainString();
        String newQuitUrl = quitUrl;
        String newReturnUrl = returnUrl + outTradeNo;


        log.info("payPostFeeUrl:" + payPostFeeUrl);
        try {
            // 单独指定回调地址
            AlipayTradeAppPayResponse pay = Factory.Payment.App().asyncNotify(payPostFeeUrl)
                    .optional("enable_pay_channels", "balance,moneyFund,bankPay,debitCardExpress").optional("return_url", newReturnUrl)
                    .pay(subject, outTradeNo, totalAmt);
            // AlipayTradeWapPayResponse res = Factory.Payment.Wap().pay(subject,
            // outTradeNo, totalAmt, newQuitUrl, newReturnUrl);

            log.info("收到付款请求：" + outTradeNo);

            if (ResponseChecker.success(pay)) {
                jsonObj.put("outTradeNo", outTradeNo);
                jsonObj.put("form", pay.body);
                jsonObj.put("returnUrl", returnUrl + payResult.getPayId());
                log.error("payPostFee:" + jsonObj.toString());
                return jsonObj;
            } else {
                // 撤销交易
                AlipayTradeCancelResponse res1 = Factory.Payment.Common().cancel(outTradeNo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return jsonObj;
    }

    // 支付回调
    @PostMapping("/without/payPostFee")
    public String payPostFee(HttpServletRequest req) {
        try {
            Map<String, String> params = genParams(req);
            log.info("收到支付宝的支付回调：");
            log.info(JSON.toJSONString(params));
            // 验签
            if (Factory.Payment.Common().verifyNotify(params)) {
                String tradeNo = params.get("trade_no");
                // 交易状态
                String tradeStatus = params.get("trade_status");
                // 商户业务ID，主要是退款通知中返回退款申请的流水号
                String outBizNo = params.get("out_biz_no");
                String refundFee = params.get("refund_fee");
                String out_trade_no = params.get("out_trade_no");
                AlipayTradeStautsEnum statusEnum = AlipayTradeStautsEnum.getEnum(tradeStatus);
                log.info(out_trade_no);
                switch (statusEnum) {
                    case SUCCESS:
                        // 支付成功，或部分退款 退款成功
                        log.info(out_trade_no + "success");
                        deliveryService.paymentsPostFee(out_trade_no, tradeNo, 1);
                        break;
                    case CLOSED:
                        log.info(out_trade_no + "closed");
                        // 未付款交易超时关闭，或支付完成后全额退款
                        break;
                    case FINISHED:
                        // 交易完结
                        log.info(out_trade_no + "finished");
                        break;
                    case BUYER_PAY:
                        // 交易创建
                        log.info(out_trade_no + "buyPay");
                        break;
                    default:
                        break;
                }
                return MALLGlobalConfig.ALIPAY_RES_SUCCESS;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return MALLGlobalConfig.ALIPAY_RES_FAILED;
    }

    private Map<String, String> genParams(HttpServletRequest req) {
        Map<String, String[]> requestParams = req.getParameterMap();
        Map<String, String> params = new HashMap<>();
        for (Map.Entry<String, String[]> entry : requestParams.entrySet()) {
            String key = entry.getKey();
            String values[] = entry.getValue();
            StringBuilder valStr = new StringBuilder();
            for (int i = 0; i < values.length; i++) {
                if (i != values.length - 1) {
                    valStr.append(values[i]).append(",");
                } else {
                    valStr.append(values[i]);
                }
            }
            params.put(key, valStr.toString());
        }
        return params;
    }

}
