package com.example.demo.service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.demo.model.*;
import com.example.demo.repository.PaymentRepository;
import com.example.demo.repository.MembershipLevelRepository;

@Service
@Transactional
public class PaymentService {
    private static final Logger logger = LoggerFactory.getLogger(PaymentService.class);
    @Autowired private PaymentRepository paymentRepository;
    @Autowired private OrderService orderService;
    @Autowired private UserService userService;
    @Autowired private AlipayService alipayService;
    @Autowired(required = false) private PayPalService payPalService;
    @Autowired private SystemSettingsService systemSettingsService;
    @Autowired private MembershipLevelRepository membershipLevelRepository;
    
    public Payment save(Payment payment) { return paymentRepository.save(payment); }
    @Transactional(readOnly = true) public Optional<Payment> findById(Long id) { return paymentRepository.findByIdWithUser(id); }
    @Transactional(readOnly = true) public Optional<Payment> findByOrderId(String orderId) { return paymentRepository.findByOrderId(orderId); }
    @Transactional(readOnly = true) public Optional<Payment> findByExternalTransactionId(String id) { return paymentRepository.findByExternalTransactionId(id); }
    @Transactional(readOnly = true) public List<Payment> findByUserId(Long userId) { return paymentRepository.findByUserIdOrderByCreatedAtDesc(userId); }
    @Transactional(readOnly = true) public List<Payment> findAll() { return paymentRepository.findAll(); }
    @Transactional(readOnly = true) public List<Payment> findByStatus(PaymentStatus status) { return paymentRepository.findByStatus(status); }
    @Transactional(readOnly = true) public long countByUserId(Long userId) { return paymentRepository.countByUserId(userId); }
    @Transactional(readOnly = true) public long countByStatus(PaymentStatus status) { return paymentRepository.countByStatus(status); }
    @Transactional(readOnly = true) public long countByUserIdAndStatus(Long userId, PaymentStatus status) { return paymentRepository.countByUserIdAndStatus(userId, status); }
    
    /**
     * 更新支付方式和描述（带事务，解决懒加载问题）
     */
    @Transactional
    public Payment updatePaymentMethod(Long paymentId, String method, String description, String username) {
        // 使用findByIdWithUserAndOrder一次性加载User和Order，避免懒加载异常
        Payment payment = paymentRepository.findByIdWithUserAndOrder(paymentId)
            .orElseThrow(() -> new RuntimeException("支付记录不存在"));
        
        // 检查权限
        if (!payment.getUser().getUsername().equals(username)) {
            throw new RuntimeException("无权限修改此支付记录");
        }
        
        // 只有PENDING状态的支付才能修改支付方式
        if (payment.getStatus() != PaymentStatus.PENDING) {
            throw new RuntimeException("只有待支付状态的订单才能修改支付方式");
        }
        
        payment.setPaymentMethod(PaymentMethod.valueOf(method));
        if (description != null && !description.isEmpty()) {
            payment.setDescription(description);
            // 同时更新关联订单的描述
            if (payment.getOrder() != null) {
                payment.getOrder().setDescription(description);
                // 由于在同一事务中，Order会自动保存
            }
        }
        
        return paymentRepository.save(payment);
    }
    
    public Payment updatePaymentStatus(Long paymentId, PaymentStatus newStatus) {
        Payment payment = paymentRepository.findById(paymentId).orElseThrow(() -> new RuntimeException("Not found"));
        payment.setStatus(newStatus);
        if (newStatus == PaymentStatus.SUCCESS) payment.setPaidAt(LocalDateTime.now());
        return paymentRepository.save(payment);
    }
    
    public Payment confirmPaymentSuccess(Long paymentId, String externalTransactionId) {
        // 使用findByIdWithUserAndOrder确保加载User和Order，避免懒加载问题
        Payment payment = paymentRepository.findByIdWithUserAndOrder(paymentId)
            .orElseThrow(() -> new RuntimeException("Not found"));
        
        boolean alreadySuccess = payment.getStatus() == PaymentStatus.SUCCESS;
        
        if (alreadySuccess) {
            logger.info("支付记录已经是成功状态: paymentId={}", paymentId);
        } else {
            // 首次确认支付成功
            payment.setStatus(PaymentStatus.SUCCESS);
            payment.setPaidAt(LocalDateTime.now());
            payment.setExternalTransactionId(externalTransactionId);
            payment = paymentRepository.save(payment);
            logger.info("支付状态更新为SUCCESS: paymentId={}", paymentId);
        }
        
        // 无论是否已经是SUCCESS状态，都要确保订单状态和会员信息已更新
        // 这样可以处理同步返回先更新状态但没有更新会员信息的情况
        try {
            updateOrderStatusForPayment(payment);
        } catch (Exception e) {
            logger.error("支付成功但更新订单状态失败: paymentId={}, error={}", paymentId, e.getMessage(), e);
        }
        
        return payment;
    }
    
    /**
     * 支付成功后更新关联订单状态为已支付
     */
    private void updateOrderStatusForPayment(Payment payment) {
        if (payment == null) {
            logger.warn("无法更新订单状态: payment为空");
            return;
        }
        
        // 检查是否已经关联了订单
        Order order = payment.getOrder();
        if (order == null) {
            // 如果没有关联订单，需要创建一个订单并关联
            logger.warn("支付记录未关联订单，尝试创建订单: paymentId={}", payment.getId());
            try {
                order = createOrderForPayment(payment);
                payment.setOrder(order);
                paymentRepository.save(payment);
                logger.info("✅ 为支付记录创建并关联订单成功: paymentId={}, orderId={}", payment.getId(), order.getId());
            } catch (Exception e) {
                logger.error("为支付记录创建订单失败: paymentId={}, error={}", payment.getId(), e.getMessage(), e);
                return;
            }
        }
        
        try {
            // 检查订单当前状态
            OrderStatus currentStatus = order.getStatus();
            logger.info("当前订单状态: orderId={}, status={}", order.getId(), currentStatus);
            
            if (currentStatus == OrderStatus.PAID) {
                // 订单已经是PAID状态，但可能会员信息没有更新
                // 直接调用handlePointsForStatusChange来确保会员信息已更新
                logger.info("订单已是PAID状态，检查并确保会员信息已更新: orderId={}", order.getId());
                // 重新触发会员更新逻辑（通过设置相同状态不会重复增加积分，因为oldStatus == newStatus）
                // 但这样不会触发handlePointsForStatusChange，所以我们需要直接调用
                // 为了避免重复增加积分，我们在OrderService中添加一个专门的方法
                orderService.ensureMembershipUpdated(order.getId());
            } else {
                // 订单不是PAID状态，正常更新
                orderService.updateOrderStatus(order.getId(), OrderStatus.PAID);
            }
            
            logger.info("✅ 订单状态处理完成: orderId={}, orderNumber={}, paymentId={}", 
                order.getId(), order.getOrderNumber(), payment.getId());
                
        } catch (Exception e) {
            logger.error("更新订单状态失败: paymentId={}, orderId={}, error={}", 
                payment.getId(), order.getId(), e.getMessage(), e);
            throw e;
        }
    }
    
    /**
     * 为没有关联订单的支付记录创建订单
     */
    private Order createOrderForPayment(Payment payment) {
        Order order = new Order();
        order.setUser(payment.getUser());
        order.setOrderNumber("ORD" + System.currentTimeMillis());
        order.setTotalAmount(payment.getAmount());
        order.setCurrency(payment.getCurrency() != null ? payment.getCurrency() : "CNY");
        order.setStatus(OrderStatus.PENDING);  // 待支付状态，后面会更新为PAID
        order.setOrderType(OrderType.SUBSCRIPTION);
        order.setDescription(payment.getDescription() != null ? payment.getDescription() : "会员订阅");
        
        return orderService.createOrder(order);
    }
    
    /**
     * 根据支付金额增加用户积分
     * 从 system_settings 读取配置的价格来判断套餐类型
     * 标准版 -> 6000积分
     * 专业版 -> 12000积分
     */
    private void addPointsForPayment(Payment payment) {
        if (payment == null || payment.getUser() == null) {
            logger.warn("无法增加积分: payment或user为空");
            return;
        }
        
        java.math.BigDecimal amount = payment.getAmount();
        if (amount == null) {
            logger.warn("无法增加积分: 支付金额为空, paymentId={}", payment.getId());
            return;
        }
        
        // 从membership_levels表读取价格和积分（必须从数据库获取，禁止硬编码）
        MembershipLevel starterLevel = membershipLevelRepository.findByName("starter")
            .orElseThrow(() -> new IllegalStateException("数据库中缺少starter会员等级配置"));
        MembershipLevel standardLevel = membershipLevelRepository.findByName("standard")
            .orElseThrow(() -> new IllegalStateException("数据库中缺少standard会员等级配置"));
        MembershipLevel proLevel = membershipLevelRepository.findByName("professional")
            .orElseThrow(() -> new IllegalStateException("数据库中缺少professional会员等级配置"));
        
        int starterPrice = starterLevel.getPrice().intValue();
        int starterPoints = starterLevel.getPointsBonus();
        int standardPrice = standardLevel.getPrice().intValue();
        int standardPoints = standardLevel.getPointsBonus();
        int proPrice = proLevel.getPrice().intValue();
        int proPoints = proLevel.getPointsBonus();
        
        logger.info("会员等级价格: 入门版={}CNY/{}积分, 标准版={}CNY/{}积分, 专业版={}CNY/{}积分", starterPrice, starterPoints, standardPrice, standardPoints, proPrice, proPoints);
        
        // 根据金额计算积分
        int points = 0;
        String planName = "";
        int amountInt = amount.intValue();
        
        // 判断套餐类型：先检查专业版（价格最高），再检查标准版，最后入门版
        // 允许10%的价格浮动范围
        if (amountInt >= proPrice * 0.9 && amountInt <= proPrice * 1.1) {
            points = proPoints;  // 专业版积分
            planName = "专业版";
        } else if (amountInt >= standardPrice * 0.9 && amountInt <= standardPrice * 1.1) {
            points = standardPoints;   // 标准版积分
            planName = "标准版";
        } else if (amountInt >= starterPrice * 0.9 && amountInt <= starterPrice * 1.1) {
            points = starterPoints;    // 入门版积分
            planName = "入门版";
        } else if (amountInt >= proPrice) {
            points = proPoints;
            planName = "专业版";
        } else if (amountInt >= standardPrice) {
            points = standardPoints;
            planName = "标准版";
        } else if (amountInt >= starterPrice) {
            points = starterPoints;
            planName = "入门版";
        } else {
            logger.info("支付金额不在套餐范围内，不增加积分: amount={}, 入门版价格={}, 标准版价格={}, 专业版价格={}", amountInt, starterPrice, standardPrice, proPrice);
            return;
        }
        
        // 增加积分
        Long userId = payment.getUser().getId();
        logger.info("开始为用户增加积分: userId={}, points={}, plan={}, paymentId={}, amount={}", userId, points, planName, payment.getId(), amountInt);
        
        userService.addPoints(userId, points);
        
        logger.info("✅ 积分增加成功: userId={}, addedPoints={}, plan={}", userId, points, planName);
    }
    
    public Payment confirmPaymentFailure(Long paymentId, String failureReason) {
        Payment payment = paymentRepository.findById(paymentId).orElseThrow(() -> new RuntimeException("Not found"));
        payment.setStatus(PaymentStatus.FAILED);
        return paymentRepository.save(payment);
    }
    
    public Payment createOrderPayment(Order order, PaymentMethod paymentMethod) {
        Payment payment = new Payment();
        payment.setOrderId(order.getOrderNumber());
        payment.setAmount(order.getTotalAmount());
        payment.setCurrency(order.getCurrency());
        payment.setPaymentMethod(paymentMethod);
        payment.setUser(order.getUser());
        payment.setOrder(order);
        payment.setStatus(PaymentStatus.PENDING);
        return paymentRepository.save(payment);
    }
    
    public void deletePayment(Long paymentId) {
        Payment payment = paymentRepository.findById(paymentId).orElseThrow(() -> new RuntimeException("Not found"));
        paymentRepository.delete(payment);
    }
    
    @Transactional(readOnly = true)
    public List<Payment> findByUsername(String username) {
        User user = userService.findByUsername(username);
        if (user == null) throw new RuntimeException("User not found");
        return paymentRepository.findByUserIdOrderByCreatedAtDesc(user.getId());
    }
    
    @Transactional
    public Payment createPayment(String username, String orderId, String amountStr, String method, String description) {
        // 检查是否已存在相同 orderId 的支付记录
        Optional<Payment> existing = paymentRepository.findByOrderId(orderId);
        if (existing.isPresent()) {
            Payment existingPayment = existing.get();
            // 如果已存在且状态是 PENDING，检查是否是同一用户且金额相同
            if (existingPayment.getStatus() == PaymentStatus.PENDING) {
                // 验证用户和金额是否匹配
                if (existingPayment.getUser().getUsername().equals(username) && 
                    existingPayment.getAmount().compareTo(new BigDecimal(amountStr)) == 0) {
                    // 检查是否已关联订单，如果没有则需要补充关联
                    if (existingPayment.getOrder() == null) {
                        logger.warn("复用的PENDING支付记录未关联订单，需要创建订单并关联: orderId={}, paymentId={}", orderId, existingPayment.getId());
                        // 不复用，创建新的支付记录和订单
                        orderId = orderId + "_" + System.currentTimeMillis();
                    } else {
                        logger.info("复用已存在的PENDING支付记录: orderId={}, paymentId={}", orderId, existingPayment.getId());
                        return existingPayment;
                    }
                } else {
                    // 用户或金额不匹配，生成新的 orderId
                    logger.warn("已存在相同orderId的PENDING支付，但用户或金额不匹配，生成新orderId: {}", orderId);
                    orderId = orderId + "_" + System.currentTimeMillis();
                }
            } else if (existingPayment.getStatus() == PaymentStatus.SUCCESS) {
                // 如果已存在成功状态的支付，绝对不能复用，必须生成新的 orderId
                logger.warn("⚠️ 已存在相同orderId的成功支付记录，生成新orderId避免冲突: orderId={}, existingPaymentId={}, status={}", 
                    orderId, existingPayment.getId(), existingPayment.getStatus());
                orderId = orderId + "_" + System.currentTimeMillis();
            } else {
                // 如果是其他状态（FAILED、CANCELLED等），生成新的 orderId
                orderId = orderId + "_" + System.currentTimeMillis();
                logger.info("已存在相同orderId但状态为{}，生成新orderId: {}", existingPayment.getStatus(), orderId);
            }
        }
        
        User user = null;
        if (username != null) { try { user = userService.findByUsername(username); } catch (Exception e) {} }
        if (user == null) { user = userService.findByUsernameOrNull(username != null ? username : "anon"); if (user == null) user = createAnonymousUser(username != null ? username : "anon"); }
        
        BigDecimal amount = new BigDecimal(amountStr);
        
        // 先创建待支付订单
        Order order = new Order();
        order.setUser(user);
        // 统一支付链路：让 Order.orderNumber 与第三方 out_trade_no / Payment.orderId 一致，便于回调与对账
        if (orderId != null && !orderId.isBlank() && orderId.length() <= 50) {
            order.setOrderNumber(orderId);
        } else {
            order.setOrderNumber("ORD" + System.currentTimeMillis());
        }
        order.setTotalAmount(amount);
        order.setCurrency("CNY");
        order.setStatus(OrderStatus.PENDING);  // 待支付状态
        order.setOrderType(OrderType.SUBSCRIPTION);

        // 使用前端传递的描述，如果没有则根据 orderId 的套餐类型 + 数据库会员等级配置生成
        if (description != null && !description.isEmpty()) {
            order.setDescription(description);
        } else {
            String resolvedDesc = null;
            try {
                String planType = null;
                if (orderId != null && orderId.contains("_")) {
                    String[] parts = orderId.split("_");
                    if (parts.length >= 2) {
                        planType = parts[1];
                    }
                }

                // 统一映射：premium -> professional
                String levelName = null;
                if (planType != null) {
                    if ("premium".equalsIgnoreCase(planType) || "professional".equalsIgnoreCase(planType)) {
                        levelName = "professional";
                    } else if ("standard".equalsIgnoreCase(planType)) {
                        levelName = "standard";
                    } else if ("starter".equalsIgnoreCase(planType)) {
                        levelName = "starter";
                    } else if ("free".equalsIgnoreCase(planType)) {
                        levelName = "free";
                    }
                }

                if (levelName != null) {
                    var levelOpt = membershipLevelRepository.findByName(levelName);
                    if (levelOpt.isPresent() && levelOpt.get().getDisplayName() != null) {
                        resolvedDesc = levelOpt.get().getDisplayName() + "会员订阅 - " + amount + "元";
                    }
                }
            } catch (Exception e) {
                logger.warn("生成订单描述失败，将使用默认描述: {}", e.getMessage());
            }

            order.setDescription(resolvedDesc != null ? resolvedDesc : ("会员订阅 - " + amount + "元"));
        }
        
        Order savedOrder = orderService.createOrder(order);
        logger.info("创建待支付订单: orderId={}, orderNumber={}, amount={}", savedOrder.getId(), savedOrder.getOrderNumber(), amount);
        
        // 创建支付记录并关联订单
        Payment payment = new Payment();
        payment.setUser(user);
        payment.setOrderId(orderId);
        payment.setAmount(amount);
        payment.setCurrency("CNY");
        payment.setPaymentMethod(PaymentMethod.valueOf(method));
        payment.setStatus(PaymentStatus.PENDING);
        payment.setCreatedAt(LocalDateTime.now());
        payment.setOrder(savedOrder);  // 关联订单
        payment.setDescription(order.getDescription());
        
        return paymentRepository.save(payment);
    }
    
    private User createAnonymousUser(String username) {
        User user = new User();
        user.setUsername(username);
        user.setEmail(username + "@anon.com");
        user.setPasswordHash("anon");
        user.setRole("ROLE_USER");
        return userService.save(user);
    }
    
    @Transactional(readOnly = true)
    public Map<String, Object> getUserPaymentStats(String username) {
        User user = userService.findByUsername(username);
        if (user == null) throw new RuntimeException("User not found");
        Map<String, Object> stats = new HashMap<>();
        stats.put("totalPayments", paymentRepository.countByUserId(user.getId()));
        stats.put("successfulPayments", paymentRepository.countByUserIdAndStatus(user.getId(), PaymentStatus.SUCCESS));
        return stats;
    }
}
