package com.fzm.mall.pay.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.fzm.mall.pay.constant.GlobalConfig;
import com.fzm.mall.pay.entity.dto.AlipayDTO;
import com.fzm.mall.pay.enums.AlipayTradeStautsEnum;
import com.fzm.mall.pay.repo.ResponseFactory;
import com.fzm.mall.pay.repo.ResponseVO;
import com.fzm.mall.pay.util.UUIDUtil;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
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 javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author wangp
 * @date 2021/3/18 14:00
 * @description 支付宝
 * @since JDK 1.8
 */
@Api(tags = "支付宝支付")
@Slf4j
@RestController
@RequestMapping("/alipay")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AlipayController {

    private final ResponseFactory resFac;

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

    @PostMapping("/pagePay")
    public ResponseVO pay(@RequestBody @Valid AlipayDTO alipayDTO) {
        String outTradeNo = alipayDTO.getOutTradeNo();
        String subject = alipayDTO.getSubject();
        String totalAmount = alipayDTO.getTotalAmount();
        JSONObject jsonObj = new JSONObject();
        try {
            //发起API调用
            AlipayTradePagePayResponse res = Factory.Payment.Page()
                    // 调用asyncNotify扩展方法，可以为每此API调用，设置独立的异步通知地址
                    // 此处设置的异步通知地址的优先级高于全局Config中配置的异步通知地址
                    .asyncNotify(payNotifyUrl)
                    .pay(
                            subject,
                            outTradeNo,
                            totalAmount,
                            returnUrl
                    );

            //处理响应或异常
            if (ResponseChecker.success(res)) {
                System.err.println(res.body);
                jsonObj.put("form", res.body);
                return resFac.getSuccessResponseWithData(jsonObj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resFac.getSimpleFailureResponse();
    }

    // 支付回调
    @PostMapping("/payNotify")
    public String payNotify(HttpServletRequest req) {
        try {
            Map<String, String> params = genParams(req);
            System.err.println("收到支付宝的支付回调");
            log.info("收到支付宝的支付回调：");
            log.info(JSON.toJSONString(params));
            // 验签
            if (Factory.Payment.Common().verifyNotify(params)) {
                return GlobalConfig.ALIPAY_RES_SUCCESS;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return GlobalConfig.ALIPAY_RES_FAIL;
    }

    @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 (Objects.requireNonNull(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 GlobalConfig.ALIPAY_RES_SUCCESS;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return GlobalConfig.ALIPAY_RES_FAIL;
    }

    @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("/query")
    public String query(@RequestParam String outTradeNo, @RequestParam String outRequestNo) {
        try {
            // 查询交易
            AlipayTradeQueryResponse res1 = Factory.Payment.Common().query(outTradeNo);
            System.err.println(res1.body);

            /*// 查询退款
            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";
    }

    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;
    }
}
