package org.springblade.modules.finance.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
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.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.enums.OrderStateEnum;
import org.springblade.common.enums.YesOrNoEnum;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.log.logger.BladeLogger;
import org.springblade.core.tool.api.R;
import org.springblade.modules.finance.entity.Order;
import org.springblade.modules.finance.entity.OrderRefund;
import org.springblade.modules.finance.entity.TransactionFlow;
import org.springblade.modules.finance.pay.entity.AlipayProperties;
import org.springblade.modules.finance.service.IAliPayService;
import org.springblade.modules.finance.service.IOrderRefundService;
import org.springblade.modules.finance.service.IOrderService;
import org.springblade.modules.finance.service.ITransactionFlowService;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * Author pangqijun
 * Date 2023/2/16
 * Description
 */
@Slf4j
@Service
public class AliPayServiceImpl implements IAliPayService {

    @Resource
    private BladeLogger bladeLogger;
    @Resource
    private AlipayProperties properties;
    @Resource
    private AlipayClient alipayClient;
    @Resource
    private IOrderRefundService orderRefundService;
    @Resource
    private ITransactionFlowService transactionFlowService;
    @Resource
    private IOrderService orderService;

    @Override
    public void refund(Order order) {
        Assert.notNull(order.getId(), "订单id参数错误");
        // 记录退款信息
        List<OrderRefund> list = orderRefundService.lambdaQuery().eq(OrderRefund::getOrderId, order.getId()).orderByDesc(OrderRefund::getCreateTime).list();
        OrderRefund orderRefund;
        if (CollUtil.isNotEmpty(list)) {
            orderRefund = list.get(0);
        } else {
            orderRefund = OrderRefund.build(order.getId());
        }
        // 构建支付宝退款请求参数
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("refund_amount", order.getPaymentAmount());
        if (StrUtil.isNotBlank(order.getTransactionNo())) {
            TransactionFlow flow = transactionFlowService.getByNo(order.getTransactionNo());
            bizContent.put("out_trade_no", new Integer(2).equals(flow.getStatus()) ? order.getTransactionNo() : order.getOrderNo());
            bizContent.put("out_request_no", orderRefund.getRefundNo());
        } else {
            bizContent.put("out_trade_no", order.getOrderNo());
        }
        request.setBizContent(bizContent.toString());
        try {
            AlipayTradeRefundResponse response = alipayClient.certificateExecute(request);
            if(response.isSuccess()){
                log.info("退款成功, 订单号[{}]", order.getOrderNo() + ",支付宝返回数据:" + JSON.toJSONString(response));
                bladeLogger.info("退款成功", "订单号:" + order.getOrderNo() + ",支付宝返回数据:" + JSON.toJSONString(response));
                order.setOrderState(OrderStateEnum.REFUNDED.getValue());
                orderRefundService.success(orderRefund);
                orderService.updateById(order);
            } else {
                log.info("退款失败, 订单号[{}], 支付宝返回数据[{}]", order.getOrderNo(), JSON.toJSONString(response));
                bladeLogger.info("退款失败", "订单号:" + order.getOrderNo() + ",支付宝返回数据:" + JSON.toJSONString(response));
                orderRefundService.failure(orderRefund, response.getSubMsg());
                throw new ServiceException("退款失败, " + response.getCode() + ":" + response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            log.error("退款异常," + e.getMessage(), e);
            bladeLogger.error("退款异常", "订单号:" + order.getOrderNo() + ",errorMessage:" + e.getMessage());
            orderRefundService.failure(orderRefund, e.getErrMsg());
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public String init(String orderNo, String amount, String callbackUrl) {
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest ();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel ();
        model.setBody("要酒");
        model.setSubject("要酒");
        model.setOutTradeNo(orderNo);
        model.setTimeoutExpress("30m");
        model.setTotalAmount(amount);
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(properties.getDomain() + callbackUrl);
        try  {
            // 证书方式调用
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            return response.getBody();
        }  catch (AlipayApiException e ) {
            log.error("发起支付失败—" + e.getMessage(), e);
            throw new ServiceException("发起支付失败");
        }
    }

    @Override
    public boolean rsaCertCheck(Map<String, String> params) throws AlipayApiException {
        return AlipaySignature.rsaCertCheckV1(params, properties.getAliPayCertPath(), AlipayConstants.CHARSET_UTF8, "RSA2");
    }

    @Override
    public void check(Map<String, String> params, Order order) {
        if (order == null) {
            throw new ServiceException("out_trade_no错误");
        }

        // 2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
        BigDecimal totalAmount = new BigDecimal(params.get("total_amount"));
        if (totalAmount.equals(order.getPaymentAmount())) {
            throw new ServiceException("金额不一致");
        }

        // 4、验证app_id是否为该商户本身。
        if (!params.get("app_id").equals(properties.getAppId())) {
            throw new ServiceException("app_id不一致");
        }
    }

    @Override
    public void check(Map<String, String> params, TransactionFlow flow) {

    }

    @Override
    public String getPayeeUserId() {
        return properties.getPayeeUserId();
    }
}
