package com.snack.server.module.order.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.snack.server.common.ResultCode;
import com.snack.server.config.AlipayProperties;
import com.snack.server.exception.BusinessException;
import com.snack.server.module.order.entity.Order;
import com.snack.server.module.order.enums.OrderStatusEnum;
import com.snack.server.module.order.enums.PayChannelEnum;
import com.snack.server.module.order.mapper.OrderMapper;
import com.snack.server.module.order.service.AlipayService;
import com.snack.server.module.order.service.OrderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 支付宝支付业务实现（电脑网站支付，沙箱）
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AlipayServiceImpl implements AlipayService {

    private static final String NOTIFY_PATH = "/api/payment/alipay/notify";

    private final AlipayProperties alipayProperties;
    private final OrderMapper orderMapper;
    private final OrderService orderService;

    @Override
    public String createPagePayUrl(Long orderId) {
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw new BusinessException(ResultCode.ORDER_NOT_EXIST);
        }
        if (!Objects.equals(order.getUserId(), StpUtil.getLoginIdAsLong())) {
            throw new BusinessException(1000, "订单不存在或无权访问");
        }
        if (!Objects.equals(order.getStatus(), OrderStatusEnum.PENDING_PAY.getCode())) {
            throw new BusinessException(ResultCode.ORDER_STATUS_ERROR, "当前订单状态不可支付");
        }

        AlipayClient alipayClient = buildClient();
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(fullNotifyUrl());
        request.setReturnUrl(alipayProperties.getReturnUrl());

        Map<String, Object> bizContent = new LinkedHashMap<>();
        bizContent.put("out_trade_no", order.getOrderNo());
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        bizContent.put("total_amount", order.getPayAmount().toPlainString());
        bizContent.put("subject", "零食商城-订单" + order.getOrderNo());
        bizContent.put("timeout_express", "30m");
        request.setBizContent(JSONUtil.toJsonStr(bizContent));

        try {
            AlipayTradePagePayResponse response = alipayClient.pageExecute(request, "GET");
            String payUrl = response.getBody();
            if (StrUtil.isBlank(payUrl)) {
                throw new BusinessException(1000, "支付宝下单失败，未生成支付链接");
            }
            log.info("生成支付宝支付链接 orderNo={}", order.getOrderNo());
            return payUrl;
        } catch (AlipayApiException e) {
            log.error("生成支付宝支付链接失败 orderNo={}", order.getOrderNo(), e);
            throw new BusinessException(1000, "支付宝下单失败：" + e.getErrMsg());
        }
    }

    @Override
    public String handleNotify(Map<String, String> params) {
        if (!rsaCheck(params)) {
            log.warn("支付宝异步通知签名校验失败");
            return "fail";
        }
        String tradeStatus = params.get("trade_status");
        if (!"TRADE_SUCCESS".equals(tradeStatus) && !"TRADE_FINISHED".equals(tradeStatus)) {
            log.info("支付宝异步通知忽略状态 trade_status={}", tradeStatus);
            return "success";
        }

        String orderNo = params.get("out_trade_no");
        String tradeNo = params.get("trade_no");
        if (StrUtil.isBlank(orderNo) || StrUtil.isBlank(tradeNo)) {
            return "fail";
        }
        Order order = findOrderByNo(orderNo);
        if (order == null) {
            log.warn("支付宝异步通知订单不存在 orderNo={}", orderNo);
            return "fail";
        }

        String totalAmount = params.get("total_amount");
        if (StrUtil.isNotBlank(totalAmount)
                && new BigDecimal(totalAmount).compareTo(order.getPayAmount()) != 0) {
            log.warn("支付宝异步通知金额不一致 orderNo={} notify={} order={}",
                    orderNo, totalAmount, order.getPayAmount());
            return "fail";
        }
        // 幂等处理：已支付订单直接返回 success，避免支付宝重复通知
        if (Objects.equals(order.getStatus(), OrderStatusEnum.PENDING_SHIP.getCode())) {
            return "success";
        }
        boolean ok = orderService.handlePaySuccess(
                order.getId(), PayChannelEnum.ALIPAY.getCode(), tradeNo);
        return ok ? "success" : "fail";
    }

    @Override
    public String handleReturn(Map<String, String> params) {
        if (!rsaCheck(params)) {
            throw new BusinessException(1000, "支付宝返回参数校验失败");
        }
        String orderNo = params.get("out_trade_no");
        String base = StrUtil.removeSuffix(alipayProperties.getReturnUrl(), "/");
        return StrUtil.isBlank(orderNo) ? base : base + "?pay=success&orderNo=" + orderNo;
    }

    @Override
    public String handleRefundNotify(Map<String, String> params) {
        if (!rsaCheck(params)) {
            log.warn("支付宝退款异步通知签名校验失败");
            return "fail";
        }
        String orderNo = params.get("out_trade_no");
        if (StrUtil.isBlank(orderNo)) {
            return "fail";
        }
        Order order = findOrderByNo(orderNo);
        if (order == null) {
            return "fail";
        }
        if (Objects.equals(order.getStatus(), OrderStatusEnum.REFUNDED.getCode())) {
            return "success";
        }
        String tradeNo = params.get("trade_no");
        boolean ok = orderService.handleRefundSuccess(
                order.getId(), StrUtil.blankToDefault(tradeNo, "RF-" + order.getOrderNo()));
        return ok ? "success" : "fail";
    }

    private AlipayClient buildClient() {
        return new DefaultAlipayClient(
                alipayProperties.getGateway(),
                alipayProperties.getAppId(),
                alipayProperties.getAppPrivateKey(),
                "json",
                alipayProperties.getCharset(),
                alipayProperties.getAlipayPublicKey(),
                alipayProperties.getSignType());
    }

    private String fullNotifyUrl() {
        String base = alipayProperties.getNotifyUrl();
        if (StrUtil.isBlank(base)) {
            throw new BusinessException(1000, "支付宝回调地址未配置");
        }
        return StrUtil.removeSuffix(base, "/") + NOTIFY_PATH;
    }

    private boolean rsaCheck(Map<String, String> params) {
        try {
            return AlipaySignature.rsaCheckV1(
                    params,
                    alipayProperties.getAlipayPublicKey(),
                    alipayProperties.getCharset(),
                    alipayProperties.getSignType());
        } catch (AlipayApiException e) {
            log.warn("支付宝签名校验异常：{}", e.getMessage());
            return false;
        }
    }

    private Order findOrderByNo(String orderNo) {
        return orderMapper.selectOne(
                new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, orderNo));
    }
}
