package com.dora.service.impl;

import com.dora.dto.PointsRechargeDto;
import com.dora.entity.Order;
import com.dora.entity.PointsConsumptionLog;
import com.dora.entity.PointsPackage;
import com.dora.entity.User;
import com.dora.mapper.OrderMapper;
import com.dora.mapper.PointsConsumptionLogMapper;
import com.dora.mapper.PointsPackageMapper;
import com.dora.mapper.UserMapper;
import com.dora.service.PointsRechargeService;
import com.dora.util.OrderUtil;
import com.hh.enums.PayType;
import com.hh.factory.factories.PayFactory;
import com.hh.factory.products.PayProduct;
import com.hh.factory.vo.req.PayReqVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 积分充值服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PointsRechargeServiceImpl implements PointsRechargeService {

    private final PointsPackageMapper pointsPackageMapper;
    private final OrderMapper orderMapper;
    private final UserMapper userMapper;
    private final PointsConsumptionLogMapper pointsConsumptionLogMapper;
    private final PayFactory payFactory;
    
    @Value("${wx2.notifyUrl:/user/pay/callback}")
    private String wechatNotifyUrl;

    @Override
    public List<PointsRechargeDto.PackageResponse> getActivePackages() {
        List<PointsPackage> packages = pointsPackageMapper.selectActivePackages();
        return packages.stream()
                .map(this::convertToResponse)
                .collect(Collectors.toList());
    }

    @Override
    public List<PointsRechargeDto.PackageResponse> getHotPackages(Integer limit) {
        if (limit == null || limit <= 0) {
            limit = 3;
        }
        List<PointsPackage> packages = pointsPackageMapper.selectHotPackages(limit);
        return packages.stream()
                .map(this::convertToResponse)
                .collect(Collectors.toList());
    }

    @Override
    public PointsRechargeDto.PackageResponse getPackageById(Long packageId) {
        PointsPackage pointsPackage = pointsPackageMapper.selectById(packageId);
        if (pointsPackage == null) {
            throw new RuntimeException("套餐不存在");
        }
        return convertToResponse(pointsPackage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PointsRechargeDto.CreateRechargeOrderResponse createRechargeOrder(
            Long userId, PointsRechargeDto.CreateRechargeOrderRequest request) {
        
        // 1. 验证用户
        User user = userMapper.findById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 2. 验证套餐
        PointsPackage pointsPackage = pointsPackageMapper.selectById(request.getPackageId());
        if (pointsPackage == null || pointsPackage.getIsActive() != 1) {
            throw new RuntimeException("套餐不存在或已下架");
        }

        // 3. 生成订单号
        String orderNo = OrderUtil.generateOrderNo();

        // 4. 创建订单
        Order order = new Order();
        order.setOrderNo(orderNo);
        order.setOrderType(2); // 积分订单
        order.setUserId(userId);
        order.setPointsPackageId(pointsPackage.getId());
        order.setPointsAmount(pointsPackage.getTotalPoints());
        order.setOriginalPrice(pointsPackage.getOriginalPrice());
        order.setAmount(pointsPackage.getPrice());
        order.setStatus(0); // 待支付
        order.setPaymentMethod(request.getPaymentMethod());
        
        // 检查是否首充，给予额外奖励
        boolean isFirstRecharge = checkIsFirstRecharge(userId);
        if (isFirstRecharge) {
            // 首充额外赠送10%积分
            int bonusPoints = (int) (pointsPackage.getTotalPoints() * 0);
            order.setPointsAmount(pointsPackage.getTotalPoints() + bonusPoints);
            order.setDiscountType("FIRST_PURCHASE");
            order.setDiscountDescription("首充奖励+" + bonusPoints + "积分");
        }

        order.setCreateTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        order.setIsDeleted(0);

        int result = orderMapper.insertOrder(order);
        if (result <= 0) {
            throw new RuntimeException("订单创建失败");
        }

        log.info("创建积分充值订单成功 - userId: {}, orderNo: {}, packageId: {}, amount: {}, points: {}", 
                userId, orderNo, pointsPackage.getId(), order.getAmount(), order.getPointsAmount());

        // 5. 生成支付参数（真实对接微信支付）
        String paymentParams = generatePaymentParams(order, request);

        // 6. 构建响应
        return PointsRechargeDto.CreateRechargeOrderResponse.builder()
                .orderNo(orderNo)
                .amount(order.getAmount())
                .pointsAmount(order.getPointsAmount())
                .paymentMethod(request.getPaymentMethod())
                .paymentParams(paymentParams)
                .createTime(order.getCreateTime())
                .build();
    }

    @Override
    public List<PointsRechargeDto.RechargeRecordResponse> getRechargeRecords(Long userId, Integer page, Integer size) {
        if (page == null || page < 1) page = 1;
        if (size == null || size < 1) size = 10;
        
        int offset = (page - 1) * size;
        
        // 查询用户的积分充值订单
        List<Order> orders = orderMapper.selectPointsOrdersByUserId(userId, offset, size);
        
        List<PointsRechargeDto.RechargeRecordResponse> records = new ArrayList<>();
        for (Order order : orders) {
            // 获取套餐信息
            String packageName = "未知套餐";
            if (order.getPointsPackageId() != null) {
                PointsPackage pkg = pointsPackageMapper.selectById(order.getPointsPackageId());
                if (pkg != null) {
                    packageName = pkg.getName();
                }
            }

            PointsRechargeDto.RechargeRecordResponse record = PointsRechargeDto.RechargeRecordResponse.builder()
                    .orderNo(order.getOrderNo())
                    .packageName(packageName)
                    .pointsAmount(order.getPointsAmount())
                    .amount(order.getAmount())
                    .paymentMethodName(getPaymentMethodName(order.getPaymentMethod()))
                    .statusName(getOrderStatusName(order.getStatus()))
                    .createTime(order.getCreateTime())
                    .paidAt(order.getPaidAt())
                    .build();
            records.add(record);
        }

        return records;
    }

    @Override
    public PointsRechargeDto.RechargeStatsResponse getRechargeStats(Long userId) {
        // 统计用户的积分充值情况
        Long totalCount = orderMapper.countPointsOrdersByUserId(userId, 1); // status=1 已完成
        BigDecimal totalAmount = orderMapper.sumPointsOrdersAmountByUserId(userId, 1);
        Long totalPoints = orderMapper.sumPointsOrdersPointsByUserId(userId, 1);
        Order lastOrder = orderMapper.selectLastPointsOrderByUserId(userId, 1);

        boolean isFirstRecharge = (totalCount == null || totalCount == 0);

        return PointsRechargeDto.RechargeStatsResponse.builder()
                .totalRechargeCount(totalCount != null ? totalCount : 0L)
                .totalAmount(totalAmount != null ? totalAmount : BigDecimal.ZERO)
                .totalPoints(totalPoints != null ? totalPoints : 0L)
                .isFirstRecharge(isFirstRecharge)
                .lastRechargeTime(lastOrder != null ? lastOrder.getPaidAt() : null)
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleRechargePaymentSuccess(String orderNo) {
        log.info("处理积分充值支付成功回调 - orderNo: {}", orderNo);

        // 1. 查询订单
        Order order = orderMapper.selectByOrderNo(orderNo);
        if (order == null) {
            log.error("订单不存在 - orderNo: {}", orderNo);
            throw new RuntimeException("订单不存在");
        }

        if (order.getOrderType() != 2) {
            log.warn("不是积分订单，跳过积分充值处理 - orderNo: {}, orderType: {}", orderNo, order.getOrderType());
            return;
        }

        if (order.getStatus() == 1) {
            log.warn("订单已处理，避免重复充值 - orderNo: {}", orderNo);
            return;
        }

        // 2. 查询用户
        User user = userMapper.findById(order.getUserId());
        if (user == null) {
            log.error("用户不存在 - userId: {}", order.getUserId());
            throw new RuntimeException("用户不存在");
        }

        // 3. 查询套餐信息（用于获取有效期）
        PointsPackage pointsPackage = pointsPackageMapper.selectById(order.getPointsPackageId());
        int expireDays = (pointsPackage != null) ? pointsPackage.getPointsExpireDays() : 365;

        // 4. 计算新的积分和有效期
        int oldPoints = user.getPoints() != null ? user.getPoints() : 0;
        int newPoints = oldPoints + order.getPointsAmount();
        
        LocalDateTime newPointsExpiresAt;
        if (user.getPointsExpiresAt() != null && user.getPointsExpiresAt().isAfter(LocalDateTime.now())) {
            // 如果当前积分未过期，在现有基础上延长
            newPointsExpiresAt = user.getPointsExpiresAt().plusDays(expireDays);
        } else {
            // 如果当前积分已过期，从当前时间开始计算
            newPointsExpiresAt = LocalDateTime.now().plusDays(expireDays);
        }

        // 5. 更新用户积分
        user.setPoints(newPoints);
        user.setPointsExpiresAt(newPointsExpiresAt);
        user.setUpdateTime(LocalDateTime.now());
        int updateResult = userMapper.updateById(user);
        if (updateResult <= 0) {
            log.error("用户积分更新失败 - userId: {}", user.getId());
            throw new RuntimeException("用户积分更新失败");
        }

        // 6. 记录积分变动日志
        PointsConsumptionLog consumptionLog = new PointsConsumptionLog();
        consumptionLog.setUserId(order.getUserId());
        consumptionLog.setTaskNo(orderNo);
        consumptionLog.setChangeType("recharge");
        consumptionLog.setChangeAmount(order.getPointsAmount());
        consumptionLog.setBalanceBefore(oldPoints);
        consumptionLog.setBalanceAfter(newPoints);
        consumptionLog.setDescription("积分充值 - " + (pointsPackage != null ? pointsPackage.getName() : "未知套餐"));
        consumptionLog.setCreateTime(LocalDateTime.now());
        consumptionLog.setIsDeleted(0);
        pointsConsumptionLogMapper.insert(consumptionLog);

        // 7. 更新订单状态
        order.setStatus(1); // 已完成
        order.setPaidAt(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        orderMapper.updateById(order);

        log.info("积分充值成功 - userId: {}, orderNo: {}, oldPoints: {}, addPoints: {}, newPoints: {}", 
                user.getId(), orderNo, oldPoints, order.getPointsAmount(), newPoints);
    }

    // ==================== 私有方法 ====================

    /**
     * 转换为响应DTO
     */
    private PointsRechargeDto.PackageResponse convertToResponse(PointsPackage pkg) {
        return PointsRechargeDto.PackageResponse.builder()
                .id(pkg.getId())
                .name(pkg.getName())
                .description(pkg.getDescription())
                .points(pkg.getPoints())
                .bonusPoints(pkg.getBonusPoints())
                .totalPoints(pkg.getTotalPoints())
                .price(pkg.getPrice())
                .originalPrice(pkg.getOriginalPrice())
                .pointsExpireDays(pkg.getPointsExpireDays())
                .discountLabel(pkg.getDiscountLabel())
                .isHot(pkg.getIsHot() == 1)
                .isActive(pkg.getIsActive() == 1)
                .build();
    }

    /**
     * 检查是否首次充值
     */
    private boolean checkIsFirstRecharge(Long userId) {
        Long count = orderMapper.countPointsOrdersByUserId(userId, 1); // status=1 已完成
        return count == null || count == 0;
    }

    /**
     * 生成支付参数（真实对接微信支付）
     */
    private String generatePaymentParams(Order order, PointsRechargeDto.CreateRechargeOrderRequest request) {
        try {
            if (request.getPaymentMethod() == 2) {
                // 微信支付
                return generateWechatPayParams(order, request);
            } else if (request.getPaymentMethod() == 1) {
                // 支付宝暂不支持
                throw new RuntimeException("当前仅支持微信支付");
            }
            throw new RuntimeException("不支持的支付方式");
        } catch (Exception e) {
            log.error("生成支付参数失败 - orderNo: {}, paymentMethod: {}", 
                    order.getOrderNo(), request.getPaymentMethod(), e);
            throw new RuntimeException("生成支付参数失败：" + e.getMessage());
        }
    }
    
    /**
     * 生成微信支付参数
     */
    private String generateWechatPayParams(Order order, PointsRechargeDto.CreateRechargeOrderRequest request) {
        try {
            // 初始化微信支付工厂
            PayProduct payProduct = payFactory.init(PayType.WX_V2);
            
            // 构建支付请求参数
            PayReqVO payReqVO = new PayReqVO();
            payReqVO.setAmounts(order.getAmount());
            payReqVO.setOrderNo(order.getOrderNo());
            payReqVO.setDescription("积分充值 - " + order.getPointsAmount() + "积分");
            payReqVO.setTradeType(request.getTradeType() != null ? request.getTradeType() : "JSAPI");
            payReqVO.setOpenid(request.getOpenid()); // 用户openid
            payReqVO.setNotifyUrl(wechatNotifyUrl); // 回调URL
            
            log.info("准备调用微信支付 - orderNo: {}, tradeType: {}, openid: {}", 
                    order.getOrderNo(), payReqVO.getTradeType(), request.getOpenid());
            
            // 调用微信支付下单接口
            Map<String, String> result = payProduct.placeOrder(payReqVO);
            
            log.info("微信支付下单成功 - orderNo: {}, result: {}", order.getOrderNo(), result);
            
            // 将结果转为JSON字符串返回给前端
            return convertMapToJson(result);
            
        } catch (Exception e) {
            log.error("调用微信支付下单接口失败 - orderNo: {}", order.getOrderNo(), e);
            throw new RuntimeException("调用微信支付接口失败：" + e.getMessage());
        }
    }
    
    /**
     * 将Map转为JSON字符串
     */
    private String convertMapToJson(Map<String, String> map) {
        if (map == null || map.isEmpty()) {
            return "{}";
        }
        
        StringBuilder json = new StringBuilder("{");
        int count = 0;
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (count > 0) {
                json.append(",");
            }
            json.append("\"").append(entry.getKey()).append("\":\"")
                .append(entry.getValue()).append("\"");
            count++;
        }
        json.append("}");
        return json.toString();
    }

    /**
     * 获取支付方式名称
     */
    private String getPaymentMethodName(Integer paymentMethod) {
        if (paymentMethod == null) return "未知";
        switch (paymentMethod) {
            case 1: return "支付宝";
            case 2: return "微信支付";
            default: return "未知";
        }
    }

    /**
     * 获取订单状态名称
     */
    private String getOrderStatusName(Integer status) {
        if (status == null) return "未知";
        switch (status) {
            case 0: return "待支付";
            case 1: return "已完成";
            case 2: return "已取消";
            case 3: return "支付失败";
            default: return "未知";
        }
    }
}

