package org.springblade.modules.api.controller;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConstants;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.constant.CommonConstant;
import org.springblade.common.enums.OrderStateEnum;
import org.springblade.common.enums.PaymentTypeEnum;
import org.springblade.common.enums.TransactionStatusEnum;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.log.logger.BladeLogger;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.finance.entity.Order;
import org.springblade.modules.finance.entity.TransactionFlow;
import org.springblade.modules.finance.service.IAliPayService;
import org.springblade.modules.finance.service.IOrderService;
import org.springblade.modules.finance.service.IPaymentRecordService;
import org.springblade.modules.finance.service.ITransactionFlowService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Author pangqijun
 * Date 2023/2/15
 * Description
 */
@Slf4j
@RestController
@RequestMapping(CommonConstant.API_URL + "/alipay")
@Api(value = "支付宝支付接口", tags = "08.支付宝支付接口")
public class AliPayController extends BladeController {

    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    /**
     * 支付回调接口
     */
    public static final String PAY_NOTIFY_URL = "/v1/aliPay/orderNotify";
    public static final String CART_PAY_NOTIFY_URL = "/v1/aliPay/cart/orderNotify";

    @Resource
    private IAliPayService aliPayService;
    @Resource
    private IOrderService orderService;
    @Resource
    private IPaymentRecordService paymentRecordService;
    @Resource
    private ITransactionFlowService transactionFlowService;
    @Resource
    private BladeLogger logger;

    @ApiLog("支付宝发起交易")
    @PostMapping("/initiate")
    @ApiOperation(value = "支付宝发起交易", notes = "支付宝发起交易(证书方式)")
    @ApiOperationSupport(order = 1)
    public R initiate(@ApiParam(value = "订单号", required = true) @RequestParam String orderNo) {
        Order order = orderService.getByOrderNo(orderNo);
        if (order == null){
            return fail("订单数据不存在！");
        }
        if (!OrderStateEnum.WAIT_PAY.getValue().equals(order.getOrderState())) {
            return fail("当前订单状态不支持发起交易");
        }
        String aliResult = aliPayService.init(orderNo, order.getPaymentAmount().toString(), PAY_NOTIFY_URL);
        // 支付记录
        paymentRecordService.init(order, 0);
        return data(aliResult);
    }

    @ApiLog("支付宝发起交易-购物车")
    @PostMapping("/cart/initiate")
    @ApiOperation(value = "支付宝发起交易-购物车", notes = "支付宝发起交易-购物车")
    @ApiOperationSupport(order = 2)
    public R initiateCart(@ApiParam(value = "流水号", required = true) @RequestParam String orderNo) {
        TransactionFlow flow = transactionFlowService.lambdaQuery().eq(TransactionFlow::getTransactionNo, orderNo).one();
        if (flow == null) {
            return R.fail("数据不存在");
        }
        if (flow.getStatus().equals(TransactionStatusEnum.NOT_PAY.getValue())) {
            return fail("当前交易状态不能发起支付");
        }
        String aliResult = aliPayService.init(orderNo, flow.getAmount().toString(), CART_PAY_NOTIFY_URL);
        return data(aliResult);
    }

    @ApiLog("支付宝购买回调")
    @RequestMapping(value = "/callback", method = {RequestMethod.GET, RequestMethod.POST})
    @ApiOperation(value = "异步通知相应-购买回调", notes = "异步通知相应,通知的间隔频率一般是：4m、10m、10m、1h、2h、6h、15h")
    @ApiOperationSupport(order = 3)
    public String orderNotify(HttpServletRequest request) {
        //获取支付宝请求信息
        Map<String,String> params = convertRequestParamsToMap(request);
        String paramsJson = JSON.toJSONString(params);
        try {
            log.info("支付宝支付回调参数[{}]", paramsJson);
            logger.info("支付宝支付回调", "订单号: " + params.get("out_trade_no") + ",回调参数:" + paramsJson);

            // 验证证书
            boolean flag = aliPayService.rsaCertCheck(params);
            if (!flag) {
                log.info("支付宝回调签名认证失败，signVerified=false, paramsJson:{}", paramsJson);
                return "failure";
            }
            log.info("支付宝回调签名认证成功");

            final String outTradeNo = params.get("out_trade_no");
            final Order order = orderService.getByOrderNo(outTradeNo);
            // 验证数据
            aliPayService.check(params, order);
            // 更新支付记录
            paymentRecordService.success(outTradeNo);
            // 校验成功就立即返回success，另起线程处理，此时已经跟支付宝关系不大
            executorService.execute(() -> {
                //获取请求参数中的商户订单号
                String tradeStatus = params.get("trade_status");
                // 支付成功
                if ("TRADE_SUCCESS".equals(tradeStatus)) {
                    // 处理支付成功逻辑
                    orderService.orderPaySuccess(order, PaymentTypeEnum.ALI_PAY.getValue());
                } else {
                    log.error("没有处理支付宝回调业务，支付宝交易状态：{},params:{}", tradeStatus, paramsJson);
                    logger.error("支付宝支付回调失败", "没有处理支付宝回调业务，支付宝交易状态：" + tradeStatus + ",params: " + paramsJson);
                }
            });
            return "success";
        } catch (Exception e) {
            log.error("支付宝回调异常,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage(), e);
            logger.error("支付宝回调异常", "paramsJson:" + paramsJson + ", errorMsg:" + e.getMessage());
            return "failure";
        }
    }


    @ApiLog("购物车购买支付宝回调")
    @RequestMapping(value = "/cart/orderNotify", method = {RequestMethod.GET, RequestMethod.POST})
    @ApiOperation(value = "异步通知相应-购物车购买回调", notes = "异步通知相应,通知的间隔频率一般是：4m、10m、10m、1h、2h、6h、15h")
    @ApiOperationSupport(order = 4)
    public String cartOrderNotify(HttpServletRequest request) throws AlipayApiException {
        String outTradeNo = "";
        //获取支付宝请求信息
        Map<String,String> params = convertRequestParamsToMap(request);
        String paramsJson = JSON.toJSONString(params);
        try {
            log.info("支付宝购物车支付回调参数[{}]", paramsJson);
            logger.info("支付宝购物车支付回调", "订单号: " + params.get("out_trade_no") + ",回调参数:" + paramsJson);

            // 验证证书
            boolean flag = aliPayService.rsaCertCheck(params);
            if (!flag) {
                log.info("支付宝回调签名认证失败，signVerified=false, paramsJson:{}", paramsJson);
                return "failure";
            }
            log.info("支付宝回调签名认证成功");

            outTradeNo = request.getParameter("out_trade_no");//获取请求参数中的商户订单号
            TransactionFlow flow = transactionFlowService.lambdaQuery().eq(TransactionFlow::getTransactionNo, outTradeNo).one();
            if (flow == null) {
                log.info("流水数据不存在[{}]", outTradeNo);
                return "error";
            }
            if (TransactionStatusEnum.PAID.getValue().equals(flow.getStatus())) {
                log.info("该订单已支付[{}]", outTradeNo);
                return "error";
            }
            List<Order> list = orderService.lambdaQuery().eq(Order::getTransactionNo, outTradeNo).list();
            log.info("订单数量 [{}]", list.size());
            // 校验成功就立即返回success，另起线程处理，此时已经跟支付宝关系不大
            executorService.execute(() -> {
                // 判断交易是否成功
                String tradeStatus = params.get("trade_status");
                // 交易成功
                if ("TRADE_SUCCESS".equals(tradeStatus)) {
                    flow.setStatus(TransactionStatusEnum.PAID.getValue());
                    flow.setPaymentTime(new Date());
                    flow.setPaymentType(CommonConstant.ALI_PAY);
                    // 更新交易状态
                    transactionFlowService.updateById(flow);
                    for (Order o : list) {
                        log.info("当前处理订单号[{}], payFlag:[{}]", o.getOrderNo(), o.getPaymentState());
                        // 处理支付成功逻辑
                        orderService.orderPaySuccess(o, PaymentTypeEnum.ALI_PAY.getValue());
                    }
                } else {
                    log.error("没有处理支付宝回调业务，支付宝交易状态：{},params:{}", tradeStatus, paramsJson);
                    logger.error("支付宝支付回调失败", "没有处理支付宝回调业务，支付宝交易状态：" + tradeStatus + ",params: " + paramsJson);
                }
            });
            return "success";
        } catch (Exception e) {
            log.error("支付宝支付回调异常, 订单号:" + outTradeNo + e.getMessage(), e);
            logger.error("支付宝支付回调异常", outTradeNo + e.getMessage());
            return "error";
        }
    }

    /**
     * 将request中的参数转换成Map
     * @param request
     * @return
     */
    private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Object o : requestParams.keySet()) {
            String name = (String) o;
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            retMap.put(name, valueStr);
        }
        return retMap;
    }
}
