package com.haha.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.haha.common.constant.CommonConstants;
import com.haha.common.enums.ActivityStatusEnum;
import com.haha.common.enums.ActivityTypeEnum;
import com.haha.common.enums.ApplyScopeEnum;
import com.haha.entity.MarketingActivity;
import com.haha.entity.Order;
import com.haha.mapper.ActivityDeviceMapper;
import com.haha.mapper.ActivityProductMapper;
import com.haha.mapper.ActivityShopMapper;
import com.haha.mapper.MarketingActivityMapper;
import com.haha.mapper.OrderMapper;
import com.haha.service.MarketingRuleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

/**
 * 营销规则服务实现类
 * 
 * 主要职责：
 * 1. 计算订单可享受的营销活动优惠（首单立减、折扣、满减等）
 * 2. 判断营销活动是否适用于当前订单（设备、门店、商品范围）
 * 3. 计算订单最终优惠金额和实付金额
 * 
 * 注意：
 * - 此服务只处理营销活动优惠，不处理优惠券
 * - 优惠券优惠由 UserCouponService 处理
 * - 订单最终实付 = 原价 - 营销活动优惠 - 优惠券优惠
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MarketingRuleServiceImpl implements MarketingRuleService {

    private final MarketingActivityMapper activityMapper;
    private final ActivityShopMapper activityShopMapper;
    private final ActivityDeviceMapper activityDeviceMapper;
    private final ActivityProductMapper activityProductMapper;
    private final OrderMapper orderMapper;

    /**
     * 计算订单在指定营销活动下的优惠金额
     * 
     * 业务流程：
     * 1. 验证订单和活动是否存在
     * 2. 检查活动是否进行中
     * 3. 检查活动是否适用于该设备
     * 4. 根据活动类型计算优惠金额：
     *    - type=1: 首单立减
     *    - type=2: 折扣价
     *    - type=3: 满减
     * 
     * @param orderId 订单ID
     * @param activityId 营销活动ID
     * @return 优惠金额，如果不适用则返回0
     */
    @Override
    public BigDecimal calculateDiscount(Long orderId, Long activityId) {
        // 1. 查询订单信息
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            return BigDecimal.ZERO;
        }

        // 2. 查询营销活动信息
        MarketingActivity activity = activityMapper.selectById(activityId);
        if (activity == null || activity.getStatus() != ActivityStatusEnum.ONGOING.getCode()) {
            // 活动不存在或未进行中，不享受优惠
            return BigDecimal.ZERO;
        }

        // 3. 检查活动是否适用于该设备
        if (!isApplicableToDevice(activity, order.getDeviceId())) {
            return BigDecimal.ZERO;
        }

        // 4. 根据活动类型计算优惠金额
        if (activity.getActivityType() == ActivityTypeEnum.FIRST_ORDER_DISCOUNT.getCode()) {
            return calculateFirstOrderDiscount(order, activity);
        }
        if (activity.getActivityType() == ActivityTypeEnum.DISCOUNT.getCode()) {
            return calculateDiscountPrice(order, activity);
        }
        if (activity.getActivityType() == ActivityTypeEnum.FULL_REDUCTION.getCode()) {
            return calculateFullReduction(order, activity);
        }
        return BigDecimal.ZERO;
    }

    /**
     * 计算首单立减优惠
     * 
     * 计算规则：
     * 1. 判断是否为用户首单（之前无完成订单）
     * 2. 如果是首单，优惠金额 = min(活动减免金额, 订单总金额)
     * 3. 优惠金额不超过订单总金额
     * 
     * @param order 订单信息
     * @param activity 营销活动信息
     * @return 优惠金额
     */
    @Override
    public BigDecimal calculateFirstOrderDiscount(Order order, MarketingActivity activity) {
        // 1. 判断是否为首单：查询用户是否有已完成的订单
        if (!isFirstOrder(order.getUserId())) {
            log.info("用户非首单，不适用首单立减活动: userId={}", order.getUserId());
            return BigDecimal.ZERO;
        }

        // 2. 获取活动设置的立减金额
        BigDecimal discount = activity.getDiscountValue();
        if (discount == null || discount.compareTo(BigDecimal.ZERO) <= 0) {
            return BigDecimal.ZERO;
        }

        // 3. 优惠金额不能超过订单总金额
        BigDecimal orderAmount = order.getTotalAmount();
        if (orderAmount.compareTo(discount) < 0) {
            // 如果订单金额小于立减金额，则优惠金额 = 订单金额（相当于免单）
            return orderAmount;
        }

        // 4. 返回活动设置的立减金额
        return discount;
    }

    /**
     * 计算折扣价优惠
     * 
     * 计算规则：
     * 1. 折扣率范围：0 < discountRate <= 1（如0.8表示8折）
     * 2. 优惠金额 = 订单总金额 × (1 - 折扣率)
     * 3. 如果有最大优惠限制，优惠金额不超过maxDiscount
     * 
     * @param order 订单信息
     * @param activity 营销活动信息
     * @return 优惠金额
     */
    @Override
    public BigDecimal calculateDiscountPrice(Order order, MarketingActivity activity) {
        // 1. 获取折扣率（如0.8表示8折）
        BigDecimal discountRate = activity.getDiscountValue();
        if (discountRate == null || discountRate.compareTo(BigDecimal.ZERO) <= 0 
                || discountRate.compareTo(BigDecimal.ONE) > 0) {
            // 折扣率不合法，不享受优惠
            return BigDecimal.ZERO;
        }

        // 2. 计算优惠金额：原价 × (1 - 折扣率)
        // 例：原价100元，8折（0.8），优惠 = 100 × (1 - 0.8) = 20元
        BigDecimal orderAmount = order.getTotalAmount();
        BigDecimal discountAmount = orderAmount.multiply(BigDecimal.ONE.subtract(discountRate))
                .setScale(2, RoundingMode.HALF_UP);

        // 3. 如果活动设置了最大优惠金额，则优惠不能超过此限制
        if (activity.getMaxDiscount() != null && activity.getMaxDiscount().compareTo(BigDecimal.ZERO) > 0) {
            if (discountAmount.compareTo(activity.getMaxDiscount()) > 0) {
                discountAmount = activity.getMaxDiscount();
            }
        }

        return discountAmount;
    }

    /**
     * 计算满减优惠
     * 
     * 计算规则：
     * 1. 订单总金额 >= 满减门槛(minAmount)
     * 2. 如果满足门槛，优惠金额 = 活动设置的减免金额(discountValue)
     * 3. 不满足门槛则无优惠
     * 
     * @param order 订单信息
     * @param activity 营销活动信息
     * @return 优惠金额
     */
    @Override
    public BigDecimal calculateFullReduction(Order order, MarketingActivity activity) {
        BigDecimal minAmount = activity.getMinAmount();        // 满减门槛
        BigDecimal discountValue = activity.getDiscountValue(); // 减免金额

        if (minAmount == null || discountValue == null || minAmount.compareTo(BigDecimal.ZERO) <= 0) {
            return BigDecimal.ZERO;
        }

        // 判断订单金额是否达到满减门槛
        BigDecimal orderAmount = order.getTotalAmount();
        if (orderAmount.compareTo(minAmount) < 0) {
            log.info("订单金额未达满减门槛: orderAmount={}, minAmount={}", orderAmount, minAmount);
            return BigDecimal.ZERO;
        }

        // 达到门槛，返回活动设置的减免金额
        return discountValue;
    }

    @Override
    public List<MarketingActivity> getApplicableActivities(Order order) {
        LocalDateTime now = LocalDateTime.now();
        List<MarketingActivity> activities = activityMapper.selectList(
                new LambdaQueryWrapper<MarketingActivity>()
                        .eq(MarketingActivity::getStatus, ActivityStatusEnum.ONGOING.getCode())
                        .le(MarketingActivity::getStartTime, now)
                        .ge(MarketingActivity::getEndTime, now)
                        .eq(MarketingActivity::getDeleted, CommonConstants.NOT_DELETED)
        );

        return activities.stream()
                .filter(activity -> isApplicableToDevice(activity, order.getDeviceId()))
                .collect(Collectors.toList());
    }

    @Override
    public boolean isApplicableToShop(MarketingActivity activity, Long shopId) {
        if (activity.getApplyScope() == null || activity.getApplyScope() == ApplyScopeEnum.ALL_SHOP.getCode()) {
            return true;
        }

        List<Long> shopIds = activityShopMapper.selectShopIdsByActivityId(activity.getId());
        return shopIds.contains(shopId);
    }

    @Override
    public boolean isApplicableToDevice(MarketingActivity activity, String deviceId) {
        if (activity.getDeviceScope() == null || activity.getDeviceScope() == 1) {
            return true;
        }

        List<String> deviceIds = activityDeviceMapper.selectDeviceIdsByActivityId(activity.getId());
        return deviceIds.contains(deviceId);
    }

    @Override
    public boolean isApplicableToProduct(MarketingActivity activity, Long productId) {
        if (activity.getProductScope() == null || activity.getProductScope() == 1) {
            return true;
        }

        List<Long> productIds = activityProductMapper.selectProductIdsByActivityId(activity.getId());
        return productIds.contains(productId);
    }

    @Override
    public boolean isFirstOrder(Long userId) {
        Long orderCount = orderMapper.selectCount(
                new LambdaQueryWrapper<Order>()
                        .eq(Order::getUserId, userId)
                        .in(Order::getStatus, List.of(1, 2, 3))
        );
        return orderCount == null || orderCount == 0;
    }

    /**
     * 计算订单所有可用营销活动的总优惠
     * 
     * 这是订单结算时的核心方法，业务流程：
     * 1. 查询所有进行中的营销活动
     * 2. 筛选出适用于该订单设备的活动
     * 3. 遍历每个活动，计算优惠金额并累加
     * 4. 计算最终实付金额 = 原价 - 总优惠
     * 5. 确保实付金额不为负数
     * 
     * 注意：
     * - 此方法只计算营销活动优惠，不包括优惠券
     * - 多个活动优惠可以叠加
     * - 优惠券的优惠需要在订单结算时额外计算
     * 
     * @param order 订单信息
     * @return 包含以下信息的Map：
     *         - originalAmount: 订单原价
     *         - totalDiscount: 总优惠金额
     *         - finalAmount: 最终实付金额
     *         - activities:  applied activity list
     */
    @Override
    public Map<String, Object> calculateOrderDiscount(Order order) {
        // 初始化返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("originalAmount", order.getTotalAmount());  // 订单原价
        result.put("totalDiscount", BigDecimal.ZERO);          // 总优惠金额
        result.put("activities", new ArrayList<>());           // 应用的活动列表

        // 1. 查询所有适用于该订单的营销活动
        List<MarketingActivity> applicableActivities = getApplicableActivities(order);
        BigDecimal totalDiscount = BigDecimal.ZERO;
        List<Map<String, Object>> appliedActivities = new ArrayList<>();

        // 2. 遍历每个活动，计算优惠金额
        for (MarketingActivity activity : applicableActivities) {
            // 计算该活动的优惠金额
            BigDecimal discount = calculateDiscount(order.getId(), activity.getId());
            if (discount.compareTo(BigDecimal.ZERO) > 0) {
                // 累加优惠金额
                totalDiscount = totalDiscount.add(discount);
                
                // 记录应用的活动信息
                Map<String, Object> activityInfo = new HashMap<>();
                activityInfo.put("id", activity.getId());
                activityInfo.put("name", activity.getActivityName());
                activityInfo.put("type", activity.getActivityType());
                activityInfo.put("typeLabel", ActivityTypeEnum.getLabelByCode(activity.getActivityType()).getLabel());
                activityInfo.put("discount", discount);
                appliedActivities.add(activityInfo);
            }
        }

        // 3. 计算最终实付金额 = 原价 - 总优惠
        BigDecimal finalAmount = order.getTotalAmount().subtract(totalDiscount);
        // 确保实付金额不为负数（优惠不能超过原价）
        if (finalAmount.compareTo(BigDecimal.ZERO) < 0) {
            finalAmount = BigDecimal.ZERO;
        }

        // 4. 组装返回结果
        result.put("totalDiscount", totalDiscount);
        result.put("finalAmount", finalAmount);
        result.put("activities", appliedActivities);

        return result;
    }
}
