package com.haha.service.payment.impl;

import com.haha.common.constant.OrderConstants;
import com.haha.common.enums.PaymentChannel;
import com.haha.entity.Order;
import com.haha.service.OrderService;
import com.haha.service.payment.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 支付业务门面服务实现
 * 统一处理支付相关业务逻辑，协调订单服务和支付策略
 */
@Slf4j
@Service
public class PaymentServiceImpl implements PaymentService {
    
    @Autowired
    private PaymentChannelFactory channelFactory;
    
    @Autowired
    private OrderService orderService;
    
    @Override
    public PaymentResult createPayment(Long orderId, PaymentChannel channel, Map<String, String> extra) {
        log.info("创建支付请求: orderId={}, channel={}", orderId, channel);
        
        // 1. 参数校验
        if (orderId == null) {
            log.error("创建支付失败: 订单ID不能为空");
            return PaymentResult.builder()
                    .success(false)
                    .errorCode("INVALID_PARAM")
                    .errorMsg("订单ID不能为空")
                    .build();
        }
        if (channel == null) {
            log.error("创建支付失败: 支付渠道不能为空, orderId={}", orderId);
            return PaymentResult.builder()
                    .success(false)
                    .errorCode("INVALID_PARAM")
                    .errorMsg("支付渠道不能为空")
                    .build();
        }
        
        // 2. 查询订单
        Order order = orderService.getById(orderId);
        if (order == null) {
            log.error("创建支付失败: 订单不存在, orderId={}", orderId);
            return PaymentResult.builder()
                    .success(false)
                    .errorCode("ORDER_NOT_FOUND")
                    .errorMsg("订单不存在")
                    .build();
        }
        
        // 3. 校验订单状态（必须是待支付状态）
        if (!OrderConstants.PAY_STATUS_UNPAID.equals(order.getPayStatus())) {
            log.error("创建支付失败: 订单状态不正确, orderId={}, payStatus={}", orderId, order.getPayStatus());
            return PaymentResult.builder()
                    .success(false)
                    .errorCode("INVALID_ORDER_STATUS")
                    .errorMsg("订单状态不正确，只有待支付订单可以发起支付")
                    .build();
        }
        
        // 4. 获取支付策略
        PaymentStrategy strategy;
        try {
            strategy = channelFactory.getStrategy(channel);
        } catch (IllegalArgumentException e) {
            log.error("创建支付失败: 不支持的支付渠道, channel={}", channel);
            return PaymentResult.builder()
                    .success(false)
                    .errorCode("UNSUPPORTED_CHANNEL")
                    .errorMsg("不支持的支付渠道: " + channel.getCode())
                    .build();
        }
        
        // 5. 构建支付请求
        PaymentRequest request = PaymentRequest.builder()
                .orderId(orderId)
                .orderNo(order.getOrderNo())
                .amount(order.getTotalAmount())
                .userId(order.getUserId())
                .channel(channel)
                .description("哈哈零售-订单支付")
                .openId(extra != null ? extra.get("openId") : null)
                .buyerId(extra != null ? extra.get("buyerId") : null)
                .extraParams(extra)
                .build();
        
        log.info("调用支付策略创建支付: orderNo={}, amount={}", order.getOrderNo(), order.getTotalAmount());
        
        // 6. 调用策略创建支付
        PaymentResult result = strategy.createPayment(request);
        
        // 7. 如果成功，更新订单的支付渠道信息
        if (result.isSuccess()) {
            order.setPayChannel(channel.getCode());
            order.setPayType(channel.getDescription());
            orderService.updateById(order);
            log.info("支付创建成功: orderId={}, channel={}", orderId, channel);
        } else {
            log.warn("支付创建失败: orderId={}, errorCode={}, errorMsg={}", 
                    orderId, result.getErrorCode(), result.getErrorMsg());
        }
        
        return result;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RefundResult refund(Long orderId, String reason) {
        log.info("发起退款请求: orderId={}, reason={}", orderId, reason);
        
        // 1. 参数校验
        if (orderId == null) {
            log.error("退款失败: 订单ID不能为空");
            return RefundResult.builder()
                    .success(false)
                    .errorCode("INVALID_PARAM")
                    .errorMsg("订单ID不能为空")
                    .build();
        }
        
        // 2. 查询订单
        Order order = orderService.getById(orderId);
        if (order == null) {
            log.error("退款失败: 订单不存在, orderId={}", orderId);
            return RefundResult.builder()
                    .success(false)
                    .errorCode("ORDER_NOT_FOUND")
                    .errorMsg("订单不存在")
                    .build();
        }
        
        // 3. 校验订单状态（必须是已支付）
        if (!OrderConstants.PAY_STATUS_PAID.equals(order.getPayStatus())) {
            log.error("退款失败: 订单状态不正确, orderId={}, payStatus={}", orderId, order.getPayStatus());
            return RefundResult.builder()
                    .success(false)
                    .errorCode("INVALID_ORDER_STATUS")
                    .errorMsg("订单状态不正确，只有已支付订单可以退款")
                    .build();
        }
        
        // 4. 根据订单的 payChannel 获取支付渠道
        PaymentChannel channel = PaymentChannel.fromCode(order.getPayChannel());
        
        // 5. 如果 channel 为 null 或 BALANCE，直接更新退款状态（余额退款不经过第三方）
        if (channel == null || channel == PaymentChannel.BALANCE) {
            log.info("余额退款，直接更新订单状态: orderId={}", orderId);
            updateOrderRefundStatus(order, reason, null);
            return RefundResult.builder()
                    .success(true)
                    .refundId("BALANCE_REFUND_" + orderId)
                    .build();
        }
        
        // 6. 获取支付策略
        PaymentStrategy strategy;
        try {
            strategy = channelFactory.getStrategy(channel);
        } catch (IllegalArgumentException e) {
            log.error("退款失败: 不支持的支付渠道, channel={}", channel);
            return RefundResult.builder()
                    .success(false)
                    .errorCode("UNSUPPORTED_CHANNEL")
                    .errorMsg("不支持的支付渠道: " + channel.getCode())
                    .build();
        }
        
        // 7. 构建退款请求
        String refundNo = generateRefundNo(order.getOrderNo());
        RefundRequest refundRequest = RefundRequest.builder()
                .orderId(orderId)
                .orderNo(order.getOrderNo())
                .transactionId(order.getTransactionId())
                .refundAmount(order.getTotalAmount())
                .totalAmount(order.getTotalAmount())
                .reason(reason)
                .refundNo(refundNo)
                .build();
        
        log.info("调用支付策略执行退款: orderNo={}, refundNo={}, amount={}", 
                order.getOrderNo(), refundNo, order.getTotalAmount());
        
        // 8. 调用策略退款
        RefundResult result = strategy.refund(refundRequest);
        
        // 9. 更新订单退款状态
        if (result.isSuccess()) {
            updateOrderRefundStatus(order, reason, result.getRefundId());
            log.info("退款成功: orderId={}, refundId={}", orderId, result.getRefundId());
        } else {
            log.warn("退款失败: orderId={}, errorCode={}, errorMsg={}", 
                    orderId, result.getErrorCode(), result.getErrorMsg());
        }
        
        return result;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PaymentCallbackResult handleCallback(PaymentChannel channel, Map<String, Object> params) {
        log.info("处理支付回调: channel={}", channel);
        
        // 1. 参数校验
        if (channel == null) {
            log.error("处理回调失败: 支付渠道不能为空");
            return PaymentCallbackResult.builder()
                    .success(false)
                    .errorMsg("支付渠道不能为空")
                    .build();
        }
        if (params == null || params.isEmpty()) {
            log.error("处理回调失败: 回调参数不能为空, channel={}", channel);
            return PaymentCallbackResult.builder()
                    .success(false)
                    .errorMsg("回调参数不能为空")
                    .build();
        }
        
        // 2. 获取策略
        PaymentStrategy strategy;
        try {
            strategy = channelFactory.getStrategy(channel);
        } catch (IllegalArgumentException e) {
            log.error("处理回调失败: 不支持的支付渠道, channel={}", channel);
            return PaymentCallbackResult.builder()
                    .success(false)
                    .errorMsg("不支持的支付渠道: " + channel.getCode())
                    .build();
        }
        
        // 3. 验证签名
        // 注意：对于微信支付 V3，verifyCallback 始终返回 true，
        // 因为 V3 SDK 的签名验证由 NotificationParser 在 parseCallback 中自动完成。
        // 如果签名验证失败，parseCallback 会返回 success=false。
        if (!strategy.verifyCallback(params)) {
            log.error("处理回调失败: 签名验证失败, channel={}", channel);
            return PaymentCallbackResult.builder()
                    .success(false)
                    .errorMsg("签名验证失败")
                    .build();
        }
        
        log.info("回调签名验证通过: channel={}", channel);
        
        // 4. 解析回调（对于微信 V3，此步骤内部包含 SDK 自动签名验证）
        PaymentCallbackResult result = strategy.parseCallback(params);
        
        // 5. 如果解析成功，更新订单状态
        // 对于微信 V3，如果 SDK 签名验证失败，parseCallback 返回 success=false，不会进入此分支
        if (result.isSuccess()) {
            String orderNo = result.getOrderNo();
            log.info("回调解析成功，更新订单状态: orderNo={}, transactionId={}", orderNo, result.getTransactionId());
            
            // 更新支付状态
            boolean updated = orderService.updatePayStatus(orderNo, OrderConstants.PAY_STATUS_PAID);
            if (!updated) {
                log.warn("更新订单支付状态失败: orderNo={}", orderNo);
            }
            
            // 更新 transactionId 和 payTime
            Order order = orderService.getOrderByOutTradeNo(orderNo);
            if (order == null) {
                // 尝试通过 orderNo 查找
                order = orderService.lambdaQuery()
                        .eq(Order::getOrderNo, orderNo)
                        .one();
            }
            
            if (order != null) {
                order.setTransactionId(result.getTransactionId());
                order.setPayTime(result.getPayTime() != null ? result.getPayTime() : LocalDateTime.now());
                orderService.updateById(order);
                log.info("订单更新成功: orderId={}, transactionId={}, payTime={}", 
                        order.getId(), order.getTransactionId(), order.getPayTime());
            } else {
                log.error("订单不存在，无法更新transactionId: orderNo={}", orderNo);
            }
        } else {
            log.warn("回调解析失败: channel={}, errorMsg={}", channel, result.getErrorMsg());
        }
        
        return result;
    }
    
    @Override
    public PaymentResult queryPaymentStatus(Long orderId) {
        log.info("查询支付状态: orderId={}", orderId);
        
        // 1. 参数校验
        if (orderId == null) {
            log.error("查询支付状态失败: 订单ID不能为空");
            return PaymentResult.builder()
                    .success(false)
                    .errorCode("INVALID_PARAM")
                    .errorMsg("订单ID不能为空")
                    .build();
        }
        
        // 2. 查询订单
        Order order = orderService.getById(orderId);
        if (order == null) {
            log.error("查询支付状态失败: 订单不存在, orderId={}", orderId);
            return PaymentResult.builder()
                    .success(false)
                    .errorCode("ORDER_NOT_FOUND")
                    .errorMsg("订单不存在")
                    .build();
        }
        
        // 3. 获取支付渠道
        PaymentChannel channel = PaymentChannel.fromCode(order.getPayChannel());
        if (channel == null) {
            log.warn("订单无支付渠道信息，返回本地状态: orderId={}, payStatus={}", orderId, order.getPayStatus());
            boolean isPaid = OrderConstants.PAY_STATUS_PAID.equals(order.getPayStatus());
            return PaymentResult.builder()
                    .success(isPaid)
                    .errorCode(isPaid ? null : "UNPAID")
                    .errorMsg(isPaid ? null : "订单未支付")
                    .build();
        }
        
        // 4. 如果是余额支付，直接返回本地状态
        if (channel == PaymentChannel.BALANCE) {
            boolean isPaid = OrderConstants.PAY_STATUS_PAID.equals(order.getPayStatus());
            log.info("余额支付，返回本地状态: orderId={}, isPaid={}", orderId, isPaid);
            return PaymentResult.builder()
                    .success(isPaid)
                    .channel(channel)
                    .errorCode(isPaid ? null : "UNPAID")
                    .errorMsg(isPaid ? null : "订单未支付")
                    .build();
        }
        
        // 5. 调用策略查询
        PaymentStrategy strategy;
        try {
            strategy = channelFactory.getStrategy(channel);
        } catch (IllegalArgumentException e) {
            log.error("查询支付状态失败: 不支持的支付渠道, channel={}", channel);
            return PaymentResult.builder()
                    .success(false)
                    .errorCode("UNSUPPORTED_CHANNEL")
                    .errorMsg("不支持的支付渠道: " + channel.getCode())
                    .build();
        }
        
        log.info("调用支付策略查询状态: orderNo={}, channel={}", order.getOrderNo(), channel);
        PaymentResult result = strategy.queryPayment(order.getOrderNo());
        result.setChannel(channel);
        
        return result;
    }
    
    @Override
    public List<PaymentChannel> getAvailableChannels() {
        log.debug("获取可用支付渠道列表");
        return channelFactory.getAvailableChannels();
    }
    
    /**
     * 更新订单退款状态
     */
    private void updateOrderRefundStatus(Order order, String reason, String refundId) {
        order.setRefundStatus("REFUNDED");
        order.setRefundAmount(order.getTotalAmount());
        order.setRefundTime(LocalDateTime.now());
        order.setRefundReason(reason);
        order.setPayStatus(OrderConstants.PAY_STATUS_REFUND);
        orderService.updateById(order);
    }
    
    /**
     * 生成退款单号
     */
    private String generateRefundNo(String orderNo) {
        return "RF" + orderNo + System.currentTimeMillis();
    }
}
