package com.haha.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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;

@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;

    @Override
    public BigDecimal calculateDiscount(Long orderId, Long activityId) {
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            return BigDecimal.ZERO;
        }

        MarketingActivity activity = activityMapper.selectById(activityId);
        if (activity == null || activity.getStatus() != ActivityStatusEnum.ONGOING.getCode()) {
            return BigDecimal.ZERO;
        }

        if (!isApplicableToDevice(activity, order.getDeviceId())) {
            return BigDecimal.ZERO;
        }

        switch (activity.getActivityType()) {
            case 1:
                return calculateFirstOrderDiscount(order, activity);
            case 2:
                return calculateDiscountPrice(order, activity);
            case 3:
                return calculateFullReduction(order, activity);
            default:
                return BigDecimal.ZERO;
        }
    }

    @Override
    public BigDecimal calculateFirstOrderDiscount(Order order, MarketingActivity activity) {
        if (!isFirstOrder(order.getUserId())) {
            log.info("用户非首单，不适用首单立减活动: userId={}", order.getUserId());
            return BigDecimal.ZERO;
        }

        BigDecimal discount = activity.getDiscountValue();
        if (discount == null || discount.compareTo(BigDecimal.ZERO) <= 0) {
            return BigDecimal.ZERO;
        }

        BigDecimal orderAmount = order.getTotalAmount();
        if (orderAmount.compareTo(discount) < 0) {
            return orderAmount;
        }

        return discount;
    }

    @Override
    public BigDecimal calculateDiscountPrice(Order order, MarketingActivity activity) {
        BigDecimal discountRate = activity.getDiscountValue();
        if (discountRate == null || discountRate.compareTo(BigDecimal.ZERO) <= 0 
                || discountRate.compareTo(BigDecimal.ONE) > 0) {
            return BigDecimal.ZERO;
        }

        BigDecimal orderAmount = order.getTotalAmount();
        BigDecimal discountAmount = orderAmount.multiply(BigDecimal.ONE.subtract(discountRate))
                .setScale(2, RoundingMode.HALF_UP);

        if (activity.getMaxDiscount() != null && activity.getMaxDiscount().compareTo(BigDecimal.ZERO) > 0) {
            if (discountAmount.compareTo(activity.getMaxDiscount()) > 0) {
                discountAmount = activity.getMaxDiscount();
            }
        }

        return discountAmount;
    }

    @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, 0)
        );

        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;
    }

    @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<>());

        List<MarketingActivity> applicableActivities = getApplicableActivities(order);
        BigDecimal totalDiscount = BigDecimal.ZERO;
        List<Map<String, Object>> appliedActivities = new ArrayList<>();

        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);
            }
        }

        BigDecimal finalAmount = order.getTotalAmount().subtract(totalDiscount);
        if (finalAmount.compareTo(BigDecimal.ZERO) < 0) {
            finalAmount = BigDecimal.ZERO;
        }

        result.put("totalDiscount", totalDiscount);
        result.put("finalAmount", finalAmount);
        result.put("activities", appliedActivities);

        return result;
    }
}
