package org.dromara.pay.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.pay.core.PayStrategy;
import org.dromara.pay.core.PayStrategyFactory;
import org.dromara.pay.domain.PayChannel;
import org.dromara.pay.domain.vo.PayNotifyResult;
import org.dromara.pay.domain.vo.PayChannelVo;
import org.dromara.pay.service.PayChannelService;
import org.dromara.pay.service.PayOrderService;
import org.springframework.web.bind.annotation.*;

/**
 * 支付回调通知
 *
 * @author pengles
 */
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/pay/notify")
public class PayNotifyController {

    private final PayOrderService payOrderService;
    private final PayChannelService payChannelService;
    private final PayStrategyFactory payStrategyFactory;
    private final org.dromara.pay.service.PayRefundService payRefundService;

    /**
     * 接收支付回调
     *
     * @param channelCode 渠道编码
     * @param channelId   渠道ID
     * @param request     请求对象
     */
    @SaIgnore
    @PostMapping("/{channelCode}/{channelId}")
    public String notify(@PathVariable String channelCode, @PathVariable Long channelId, HttpServletRequest request) {
        log.info("收到支付回调: channelCode={}, channelId={}", channelCode, channelId);
        
        // 1. 获取渠道配置
        PayChannelVo channelVo = payChannelService.queryById(channelId);
        if (channelVo == null) {
            log.error("支付回调失败，渠道不存在: {}", channelId);
            return "failure";
        }
        if (!channelVo.getCode().equals(channelCode)) {
             log.error("支付回调失败，渠道编码不匹配: {} != {}", channelVo.getCode(), channelCode);
             return "failure";
        }
        PayChannel channel = MapstructUtils.convert(channelVo, PayChannel.class);

        // 2. 获取策略处理回调
        try {
            PayStrategy strategy = payStrategyFactory.getStrategy(channelCode);
            PayNotifyResult result = strategy.processNotify(request, channel);
            
            if (result.isSuccess()) {
                // 3. 更新订单状态
                // 这里需要根据 orderNo 查询订单，确保存在且未支付
                // 暂时假设 PayOrderService 有方法处理状态更新，或者我们直接在这里处理
                // 由于 PayOrderService 主要是 CRUD，这里我们可能需要扩展它或直接操作
                
                // 简单实现：查询订单 -> 更新状态
                // 注意：需要幂等处理 (result.isSuccess() 只是验签通过，业务状态可能已经更新)
                handleOrderSuccess(result.getOrderNo(), result.getTradeNo(), channelCode);
                
                return result.getResponseBody();
            } else {
                log.error("支付回调验签失败: {}", channelCode);
                return result.getResponseBody(); // 通常是 failure
            }
        } catch (Exception e) {
            log.error("支付回调处理异常", e);
            return "failure";
        }
    }
    
    private void handleOrderSuccess(String orderNo, String channelOrderNo, String channelCode) {
        payOrderService.notifyOrderSuccess(orderNo, channelOrderNo);
    }

    /**
     * 接收退款回调
     *
     * @param channelCode 渠道编码
     * @param channelId   渠道ID
     * @param request     请求对象
     */
    @SaIgnore
    @PostMapping("/refund/{channelCode}/{channelId}")
    public String refundNotify(@PathVariable String channelCode, @PathVariable Long channelId, HttpServletRequest request) {
        log.info("收到退款回调: channelCode={}, channelId={}", channelCode, channelId);
        
        // 1. 获取渠道配置
        PayChannelVo channelVo = payChannelService.queryById(channelId);
        if (channelVo == null) {
            log.error("退款回调失败，渠道不存在: {}", channelId);
            return "failure";
        }
        if (!channelVo.getCode().equals(channelCode)) {
            log.error("退款回调失败，渠道编码不匹配: {} != {}", channelVo.getCode(), channelCode);
            return "failure";
        }
        PayChannel channel = MapstructUtils.convert(channelVo, PayChannel.class);

        // 2. 获取策略处理回调（退款回调通常与支付回调类似，但需要解析退款单号）
        try {
            PayStrategy strategy = payStrategyFactory.getStrategy(channelCode);
            PayNotifyResult result = strategy.processNotify(request, channel);
            
            if (result.isSuccess()) {
                // 3. 更新退款状态
                // 注意：退款回调中，orderNo可能是退款单号，需要根据实际情况调整
                // 这里假设result.getOrderNo()是退款单号
                handleRefundSuccess(result.getOrderNo(), result.getTradeNo(), channelCode);
                
                return result.getResponseBody();
            } else {
                log.error("退款回调验签失败: {}", channelCode);
                return result.getResponseBody();
            }
        } catch (Exception e) {
            log.error("退款回调处理异常", e);
            return "failure";
        }
    }
    
    private void handleRefundSuccess(String refundNo, String channelRefundNo, String channelCode) {
        payRefundService.notifyRefundSuccess(refundNo, channelRefundNo);
    }
}
