package com.ycwl.basic.pricing.service.impl;

import com.ycwl.basic.pricing.dto.DiscountDetectionContext;
import com.ycwl.basic.pricing.dto.ProductItem;
import com.ycwl.basic.pricing.dto.VoucherInfo;
import com.ycwl.basic.pricing.dto.resp.VoucherDetailResp;
import com.ycwl.basic.pricing.dto.resp.VoucherUsageSummaryResp;
import com.ycwl.basic.pricing.dto.resp.VoucherBatchOverviewResp;
import com.ycwl.basic.pricing.enums.ProductType;
import com.ycwl.basic.pricing.entity.PriceVoucherBatchConfig;
import com.ycwl.basic.pricing.entity.PriceVoucherCode;
import com.ycwl.basic.pricing.enums.VoucherCodeStatus;
import com.ycwl.basic.pricing.enums.VoucherDiscountType;
import com.ycwl.basic.pricing.mapper.PriceVoucherBatchConfigMapper;
import com.ycwl.basic.pricing.mapper.PriceVoucherCodeMapper;
import com.ycwl.basic.pricing.mapper.PriceVoucherUsageRecordMapper;
import com.ycwl.basic.pricing.entity.PriceVoucherUsageRecord;
import com.ycwl.basic.pricing.service.IVoucherService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.ycwl.basic.pricing.dto.DiscountDetectionContext;
import com.ycwl.basic.pricing.dto.ProductItem;
import com.ycwl.basic.pricing.dto.VoucherInfo;
import com.ycwl.basic.pricing.enums.ProductType;
import com.ycwl.basic.pricing.entity.PriceVoucherBatchConfig;
import com.ycwl.basic.pricing.entity.PriceVoucherCode;
import com.ycwl.basic.pricing.enums.VoucherCodeStatus;
import com.ycwl.basic.pricing.enums.VoucherDiscountType;
import com.ycwl.basic.pricing.mapper.PriceVoucherBatchConfigMapper;
import com.ycwl.basic.pricing.mapper.PriceVoucherCodeMapper;
import com.ycwl.basic.pricing.mapper.PriceVoucherUsageRecordMapper;
import com.ycwl.basic.pricing.entity.PriceVoucherUsageRecord;
import com.ycwl.basic.pricing.service.IVoucherService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 券码服务实现
 */
@Slf4j
@Service
@Lazy
@RequiredArgsConstructor
public class VoucherServiceImpl implements IVoucherService {
    
    private final PriceVoucherCodeMapper voucherCodeMapper;
    private final PriceVoucherBatchConfigMapper voucherBatchConfigMapper;
    private final PriceVoucherUsageRecordMapper usageRecordMapper;
    
    @Override
    public VoucherInfo validateAndGetVoucherInfo(String voucherCode, Long faceId, Long scenicId) {
        if (!StringUtils.hasText(voucherCode)) {
            return null;
        }
        
        // 查询券码信息
        PriceVoucherCode voucherCodeEntity = voucherCodeMapper.selectByCode(voucherCode);
        if (voucherCodeEntity == null || voucherCodeEntity.getDeleted() == 1) {
            return null;
        }
        
        // 查询批次信息
        PriceVoucherBatchConfig batchConfig = voucherBatchConfigMapper.selectById(voucherCodeEntity.getBatchId());
        if (batchConfig == null || batchConfig.getDeleted() == 1 || batchConfig.getStatus() == 0) {
            return null;
        }
        
        VoucherInfo voucherInfo = buildVoucherInfo(voucherCodeEntity, batchConfig);
        
        // 检查券码批次的时间范围，提供详细的时间范围信息
        if (!batchConfig.isWithinValidTimeRange()) {
            voucherInfo.setAvailable(false);
            Date now = new Date();
            if (batchConfig.getValidStartTime() != null && now.before(batchConfig.getValidStartTime())) {
                voucherInfo.setUnavailableReason("券码尚未生效");
            } else if (batchConfig.getValidEndTime() != null && now.after(batchConfig.getValidEndTime())) {
                voucherInfo.setUnavailableReason("券码已过期");
            } else {
                voucherInfo.setUnavailableReason("券码不在有效期内");
            }
            return voucherInfo;
        }
        
        // 验证景区匹配
        if (scenicId != null && !scenicId.equals(voucherCodeEntity.getScenicId())) {
            return null;
        }
        
        // 检查券码状态和可用性，包含完整的重复使用权限验证
        if (VoucherCodeStatus.UNCLAIMED.getCode().equals(voucherCodeEntity.getStatus())) {
            // 未领取状态，也需要检查用户的重复使用权限
            if (faceId == null) {
                voucherInfo.setAvailable(false);
                voucherInfo.setUnavailableReason("用户信息缺失，无法验证券码权限");
            } else {
                // 对于未领取的券码，检查用户在该批次下的使用权限
                String availabilityCheck = checkUserUsagePermission(voucherCodeEntity, batchConfig, faceId, false);
                if (availabilityCheck == null) {
                    voucherInfo.setAvailable(true);
                    log.debug("未领取券码验证通过: code={}, faceId={}", voucherCode, faceId);
                } else {
                    voucherInfo.setAvailable(false);
                    voucherInfo.setUnavailableReason(availabilityCheck);
                    log.info("未领取券码使用受限: code={}, faceId={}, reason={}", 
                        voucherCode, faceId, availabilityCheck);
                }
            }
        } else if (VoucherCodeStatus.canUse(voucherCodeEntity.getStatus())) {
            // 已领取可使用状态，进行完整的权限验证
            if (faceId == null) {
                voucherInfo.setAvailable(false);
                voucherInfo.setUnavailableReason("用户信息缺失，无法验证券码权限");
            } else if (!faceId.equals(voucherCodeEntity.getUserId())) {
                voucherInfo.setAvailable(false);
                voucherInfo.setUnavailableReason("券码已被其他用户领取");
            } else {
                // 执行详细的重复使用权限验证（已领取状态）
                String availabilityCheck = checkUserUsagePermission(voucherCodeEntity, batchConfig, faceId, true);
                if (availabilityCheck == null) {
                    voucherInfo.setAvailable(true);
                    log.debug("券码验证通过: code={}, faceId={}, currentUseCount={}, maxUseCount={}", 
                        voucherCode, faceId, voucherCodeEntity.getCurrentUseCount(), batchConfig.getMaxUseCount());
                } else {
                    voucherInfo.setAvailable(false);
                    voucherInfo.setUnavailableReason(availabilityCheck);
                    log.info("券码使用受限: code={}, faceId={}, reason={}", 
                        voucherCode, faceId, availabilityCheck);
                }
            }
        } else if (VoucherCodeStatus.isExhausted(voucherCodeEntity.getStatus())) {
            // 已用完或已使用
            voucherInfo.setAvailable(false);
            if (batchConfig.getMaxUseCount() != null && batchConfig.getMaxUseCount() == 1) {
                voucherInfo.setUnavailableReason("券码已使用");
            } else {
                voucherInfo.setUnavailableReason("券码使用次数已达上限");
            }
        } else if (VoucherCodeStatus.isExpired(voucherCodeEntity.getStatus())) {
            // 已过期
            voucherInfo.setAvailable(false);
            voucherInfo.setUnavailableReason("券码已过期");
        } else {
            // 其他状态
            voucherInfo.setAvailable(false);
            voucherInfo.setUnavailableReason("券码状态异常");
        }
        
        return voucherInfo;
    }
    
    @Override
    public List<VoucherInfo> getAvailableVouchers(Long faceId, Long scenicId) {
        if (faceId == null || scenicId == null) {
            return new ArrayList<>();
        }
        
        List<PriceVoucherCode> voucherCodes = voucherCodeMapper.selectAvailableVouchersByUserIdAndScenicId(faceId, scenicId);
        List<VoucherInfo> voucherInfos = new ArrayList<>();
        
        for (PriceVoucherCode voucherCode : voucherCodes) {
            PriceVoucherBatchConfig batchConfig = voucherBatchConfigMapper.selectById(voucherCode.getBatchId());
            if (batchConfig != null && batchConfig.getDeleted() == 0 && batchConfig.getStatus() == 1) {
                VoucherInfo voucherInfo = buildVoucherInfo(voucherCode, batchConfig);
                voucherInfo.setAvailable(true);
                voucherInfos.add(voucherInfo);
            }
        }
        
        return voucherInfos;
    }

    @Override
    public void markVoucherAsUsed(String voucherCode, String remark, Long faceId) {
        markVoucherAsUsed(voucherCode, remark, null, null, faceId);
    }
    
    /**
 * 标记券码为已使用（支持可重复使用）
 * 
 * @param voucherCode 券码
 * @param remark 使用备注
 * @param orderId 订单ID
 * @param discountAmount 优惠金额
 * @param faceId 人脸ID
 */
@Override
public void markVoucherAsUsed(String voucherCode, String remark, String orderId, BigDecimal discountAmount, Long faceId) {
    if (!StringUtils.hasText(voucherCode)) {
        return;
    }
    
    PriceVoucherCode voucherCodeEntity = voucherCodeMapper.selectByCode(voucherCode);
    if (voucherCodeEntity == null || voucherCodeEntity.getDeleted() == 1) {
        log.warn("券码不存在或已删除: {}", voucherCode);
        return;
    }
    
    PriceVoucherBatchConfig batchConfig = voucherBatchConfigMapper.selectById(voucherCodeEntity.getBatchId());
    if (batchConfig == null || batchConfig.getDeleted() == 1) {
        log.warn("券码批次不存在或已删除: batchId={}", voucherCodeEntity.getBatchId());
        return;
    }
    
    Date now = new Date();
    
    // 计算新的使用次数和序号
    Integer currentUseCount = voucherCodeEntity.getCurrentUseCount() != null ? 
        voucherCodeEntity.getCurrentUseCount() : 0;
    Integer newUseCount = currentUseCount + 1;
    
    // 创建使用记录
    PriceVoucherUsageRecord usageRecord = new PriceVoucherUsageRecord();
    usageRecord.setVoucherCodeId(voucherCodeEntity.getId());
    usageRecord.setVoucherCode(voucherCode);
    usageRecord.setFaceId(faceId != null ? faceId : voucherCodeEntity.getUserId());
    usageRecord.setScenicId(voucherCodeEntity.getScenicId());
    usageRecord.setBatchId(voucherCodeEntity.getBatchId());
    usageRecord.setUsageSequence(newUseCount); // 设置使用序号，表示这是该券码的第几次使用
    usageRecord.setUseTime(now);
    usageRecord.setOrderId(orderId);
    usageRecord.setDiscountAmount(discountAmount);
    usageRecord.setRemark(remark);
    usageRecord.setCreateTime(now);
    usageRecord.setDeleted(0);
    
    usageRecordMapper.insert(usageRecord);
    
    // 更新券码使用次数和状态
    voucherCodeEntity.setCurrentUseCount(newUseCount);
    voucherCodeEntity.setLastUsedTime(now);
    
    // 检查是否达到最大使用次数
    Integer maxUseCount = batchConfig.getMaxUseCount();
    if (maxUseCount != null && newUseCount >= maxUseCount) {
        if (maxUseCount == 1) {
            // 兼容原有逻辑，单次使用设为USED状态
            voucherCodeEntity.setStatus(VoucherCodeStatus.USED.getCode());
            voucherCodeEntity.setUsedTime(now);
        } else {
            // 多次使用达到上限设为CLAIMED_EXHAUSTED状态
            voucherCodeEntity.setStatus(VoucherCodeStatus.CLAIMED_EXHAUSTED.getCode());
        }
    }
    
    voucherCodeMapper.updateById(voucherCodeEntity);
    
    // 更新批次统计（使用记录数，不是使用券码数）
    voucherBatchConfigMapper.updateUsedCount(voucherCodeEntity.getBatchId(), 1);
    
    log.info("券码使用记录已创建: code={}, useCount={}, maxUseCount={}, faceId={}, sequence={}", 
        voucherCode, newUseCount, maxUseCount, faceId, newUseCount);
}
    
    @Override
    public boolean canClaimVoucher(Long faceId, Long scenicId) {
        if (faceId == null || scenicId == null) {
            return false;
        }
        
        Integer count = voucherCodeMapper.countByUserIdAndScenicId(faceId, scenicId);
        return count == 0;
    }
    
    /**
     * 获取该faceId在scenicId下的券码详情列表
     * @param faceId 用户面部ID
     * @param scenicId 景区ID
     * @return 券码详情列表，包含所有状态的券码（已领取未使用、已使用等），如果没有券码则返回空列表
     */
    public List<VoucherInfo> getVoucherDetails(Long faceId, Long scenicId) {
        if (faceId == null || scenicId == null) {
            return new ArrayList<>();
        }
        
        List<PriceVoucherCode> voucherCodes = voucherCodeMapper.selectUserVouchers(faceId, scenicId);
        List<VoucherInfo> voucherInfos = new ArrayList<>();
        
        for (PriceVoucherCode voucherCode : voucherCodes) {
            PriceVoucherBatchConfig batchConfig = voucherBatchConfigMapper.selectById(voucherCode.getBatchId());
            if (batchConfig != null && batchConfig.getDeleted() == 0) {
                VoucherInfo voucherInfo = buildVoucherInfo(voucherCode, batchConfig);
                
                // 设置可用性状态
                VoucherCodeStatus statusEnum = VoucherCodeStatus.getByCode(voucherCode.getStatus());
                if (statusEnum != null) {
                    switch (statusEnum) {
                        case CLAIMED_UNUSED:
                            voucherInfo.setAvailable(true);
                            break;
                        case USED:
                            voucherInfo.setAvailable(false);
                            voucherInfo.setUnavailableReason("券码已使用");
                            break;
                        case UNCLAIMED:
                            voucherInfo.setAvailable(false);
                            voucherInfo.setUnavailableReason("券码未领取");
                            break;
                        default:
                            voucherInfo.setAvailable(false);
                            voucherInfo.setUnavailableReason("券码状态异常");
                    }
                } else {
                    voucherInfo.setAvailable(false);
                    voucherInfo.setUnavailableReason("券码状态未知");
                }
                
                voucherInfos.add(voucherInfo);
            }
        }
        
        return voucherInfos;
    }
    
    @Override
    public BigDecimal calculateVoucherDiscount(VoucherInfo voucherInfo, DiscountDetectionContext context) {
        if (voucherInfo == null || !Boolean.TRUE.equals(voucherInfo.getAvailable()) || 
            context.getProducts() == null || context.getProducts().isEmpty()) {
            return BigDecimal.ZERO;
        }
        
        VoucherDiscountType discountType = voucherInfo.getDiscountType();
        BigDecimal discountValue = voucherInfo.getDiscountValue();
        
        if (discountType == null) {
            return BigDecimal.ZERO;
        }
        
        // 筛选适用的商品
        List<ProductItem> applicableItems = filterApplicableProducts(context.getProducts(), voucherInfo.getApplicableProducts());
        if (applicableItems.isEmpty()) {
            log.debug("券码 {} 没有适用的商品", voucherInfo.getVoucherCode());
            return BigDecimal.ZERO;
        }
        
        return switch (discountType) {
            case FREE_ALL -> {
                // 全场免费，计算适用商品的总金额
                BigDecimal applicableAmount = calculateApplicableAmount(applicableItems, context);
                yield applicableAmount;
            }
            case REDUCE_PRICE -> {
                // 商品降价，每个适用商品减免固定金额
                if (discountValue == null || discountValue.compareTo(BigDecimal.ZERO) <= 0) {
                    yield BigDecimal.ZERO;
                }
                BigDecimal totalDiscount = BigDecimal.ZERO;
                for (ProductItem product : applicableItems) {
                    BigDecimal productDiscount = discountValue.multiply(BigDecimal.valueOf(product.getQuantity()));
                    totalDiscount = totalDiscount.add(productDiscount);
                }
                yield totalDiscount;
            }
            case DISCOUNT -> {
                // 商品打折，按适用商品的金额比例计算
                if (discountValue == null || discountValue.compareTo(BigDecimal.ZERO) <= 0 || 
                    discountValue.compareTo(BigDecimal.valueOf(100)) >= 0) {
                    yield BigDecimal.ZERO;
                }
                BigDecimal applicableAmount = calculateApplicableAmount(applicableItems, context);
                BigDecimal discountRate = discountValue.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP);
                yield applicableAmount.multiply(discountRate).setScale(2, RoundingMode.HALF_UP);
            }
        };
    }
    
    @Override
    public VoucherDetailResp getVoucherDetail(String voucherCode, Long faceId) {
        if (!StringUtils.hasText(voucherCode)) {
            return null;
        }
        
        PriceVoucherCode voucherCodeEntity = voucherCodeMapper.selectByCode(voucherCode);
        if (voucherCodeEntity == null || voucherCodeEntity.getDeleted() == 1) {
            return null;
        }
        
        PriceVoucherBatchConfig batchConfig = voucherBatchConfigMapper.selectById(voucherCodeEntity.getBatchId());
        if (batchConfig == null || batchConfig.getDeleted() == 1) {
            return null;
        }
        
        VoucherDetailResp detail = new VoucherDetailResp();
        detail.setVoucherCode(voucherCode);
        
        // 设置批次信息
        VoucherDetailResp.BatchInfo batchInfo = new VoucherDetailResp.BatchInfo();
        batchInfo.setBatchId(batchConfig.getId());
        batchInfo.setBatchName(batchConfig.getBatchName());
        batchInfo.setDiscountType(batchConfig.getDiscountType());
        batchInfo.setDiscountValue(batchConfig.getDiscountValue());
        batchInfo.setApplicableProducts(batchConfig.getApplicableProducts());
        detail.setBatchInfo(batchInfo);
        
        // 设置使用信息
        VoucherDetailResp.UsageInfo usageInfo = new VoucherDetailResp.UsageInfo();
        Integer currentUseCount = voucherCodeEntity.getCurrentUseCount() != null ? voucherCodeEntity.getCurrentUseCount() : 0;
        usageInfo.setMaxUseCount(batchConfig.getMaxUseCount());
        usageInfo.setCurrentUseCount(currentUseCount);
        usageInfo.setMaxUsePerUser(batchConfig.getMaxUsePerUser());
        usageInfo.setUseIntervalHours(batchConfig.getUseIntervalHours());
        
        // 计算剩余使用次数和是否还能使用
        if (batchConfig.getMaxUseCount() != null) {
            int remaining = batchConfig.getMaxUseCount() - currentUseCount;
            usageInfo.setRemainingUseCount(Math.max(0, remaining));
            usageInfo.setCanUseMore(currentUseCount < batchConfig.getMaxUseCount());
        } else {
            usageInfo.setRemainingUseCount(null);
            usageInfo.setCanUseMore(true);
        }
        detail.setUsageInfo(usageInfo);
        
        // 设置用户信息
        if (faceId != null) {
            VoucherDetailResp.UserInfo userInfo = new VoucherDetailResp.UserInfo();
            userInfo.setUserId(faceId);
            
            // 计算该用户使用此券码的次数
            List<PriceVoucherUsageRecord> userUsageRecords = usageRecordMapper.selectByVoucherCodeAndFaceId(voucherCodeEntity.getId(), faceId);
            userInfo.setUserUsageCount(userUsageRecords.size());
            
            if (voucherCodeEntity.getLastUsedTime() != null) {
                userInfo.setLastUsedTime(voucherCodeEntity.getLastUsedTime());
                
                // 计算下次可用时间
                if (batchConfig.getUseIntervalHours() != null) {
                    Date nextAvailableTime = new Date(voucherCodeEntity.getLastUsedTime().getTime() + 
                        batchConfig.getUseIntervalHours() * 60 * 60 * 1000L);
                    userInfo.setNextAvailableTime(nextAvailableTime);
                }
            }
            detail.setUserInfo(userInfo);
        }
        
        // 设置状态信息
        VoucherDetailResp.StatusInfo statusInfo = new VoucherDetailResp.StatusInfo();
        statusInfo.setStatus(voucherCodeEntity.getStatus());
        VoucherCodeStatus statusEnum = VoucherCodeStatus.getByCode(voucherCodeEntity.getStatus());
        if (statusEnum != null) {
            statusInfo.setStatusName(statusEnum.getName());
        }
        statusInfo.setClaimedTime(voucherCodeEntity.getClaimedTime());
        detail.setStatusInfo(statusInfo);
        
        return detail;
    }
    
    @Override
    public VoucherUsageSummaryResp getVoucherUsageSummary(String voucherCode) {
        if (!StringUtils.hasText(voucherCode)) {
            return null;
        }
        
        PriceVoucherCode voucherCodeEntity = voucherCodeMapper.selectByCode(voucherCode);
        if (voucherCodeEntity == null || voucherCodeEntity.getDeleted() == 1) {
            return null;
        }
        
        PriceVoucherBatchConfig batchConfig = voucherBatchConfigMapper.selectById(voucherCodeEntity.getBatchId());
        if (batchConfig == null || batchConfig.getDeleted() == 1) {
            return null;
        }
        
        VoucherUsageSummaryResp summary = new VoucherUsageSummaryResp();
        summary.setVoucherCode(voucherCode);
        summary.setBatchId(batchConfig.getId());
        summary.setBatchName(batchConfig.getBatchName());
        
        // 获取使用记录
        List<PriceVoucherUsageRecord> usageRecords = usageRecordMapper.selectByVoucherCodeId(voucherCodeEntity.getId());
        summary.setTotalUsageRecords(usageRecords.size());
        
        // 计算独立用户数
        long uniqueUsers = usageRecords.stream()
            .mapToLong(PriceVoucherUsageRecord::getFaceId)
            .distinct()
            .count();
        summary.setUniqueUsers((int) uniqueUsers);
        
        // 设置使用统计
        VoucherUsageSummaryResp.UsageStatistics statistics = new VoucherUsageSummaryResp.UsageStatistics();
        Integer currentUseCount = voucherCodeEntity.getCurrentUseCount() != null ? voucherCodeEntity.getCurrentUseCount() : 0;
        statistics.setMaxUseCount(batchConfig.getMaxUseCount());
        statistics.setCurrentUseCount(currentUseCount);
        
        if (batchConfig.getMaxUseCount() != null) {
            int remaining = batchConfig.getMaxUseCount() - currentUseCount;
            statistics.setRemainingUseCount(Math.max(0, remaining));
            statistics.setCanUseMore(currentUseCount < batchConfig.getMaxUseCount());
            
            // 计算使用率
            if (batchConfig.getMaxUseCount() > 0) {
                BigDecimal usageRate = new BigDecimal(currentUseCount)
                    .divide(new BigDecimal(batchConfig.getMaxUseCount()), 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal(100));
                statistics.setUsageRate(usageRate);
            }
        } else {
            statistics.setRemainingUseCount(null);
            statistics.setCanUseMore(true);
            statistics.setUsageRate(null);
        }
        summary.setUsageStatistics(statistics);
        
        // 设置使用时间轴
        List<VoucherUsageSummaryResp.UsageTimeline> timeline = usageRecords.stream()
            .map(record -> {
                VoucherUsageSummaryResp.UsageTimeline item = new VoucherUsageSummaryResp.UsageTimeline();
                item.setUseTime(record.getUseTime());
                item.setFaceId(record.getFaceId());
                item.setOrderId(record.getOrderId());
                item.setDiscountAmount(record.getDiscountAmount());
                return item;
            })
            .collect(Collectors.toList());
        summary.setUsageTimeline(timeline);
        
        return summary;
    }
    
    @Override
    public VoucherBatchOverviewResp getBatchOverview(Long batchId) {
        if (batchId == null) {
            return null;
        }
        
        PriceVoucherBatchConfig batchConfig = voucherBatchConfigMapper.selectById(batchId);
        if (batchConfig == null || batchConfig.getDeleted() == 1) {
            return null;
        }
        
        VoucherBatchOverviewResp overview = new VoucherBatchOverviewResp();
        overview.setBatchId(batchId);
        overview.setBatchName(batchConfig.getBatchName());
        overview.setTotalCodes(batchConfig.getTotalCount());
        overview.setClaimedCodes(batchConfig.getClaimedCount());
        
        // 查询批次下的券码统计
        List<PriceVoucherCode> allCodes = voucherCodeMapper.selectByBatchId(batchId);
        
        // 计算已使用券码数（至少使用过一次）
        int usedCodes = (int) allCodes.stream()
            .filter(code -> code.getCurrentUseCount() != null && code.getCurrentUseCount() > 0)
            .count();
        overview.setUsedCodes(usedCodes);
        
        // 计算已达到最大使用次数的券码数
        int exhaustedCodes = 0;
        if (batchConfig.getMaxUseCount() != null) {
            exhaustedCodes = (int) allCodes.stream()
                .filter(code -> code.getCurrentUseCount() != null && 
                    code.getCurrentUseCount() >= batchConfig.getMaxUseCount())
                .count();
        }
        overview.setExhaustedCodes(exhaustedCodes);
        
        // 设置总使用记录数
        overview.setTotalUsageRecords(batchConfig.getUsedCount());
        
        // 计算平均每个券码使用次数
        if (usedCodes > 0) {
            BigDecimal averageUsage = new BigDecimal(batchConfig.getUsedCount())
                .divide(new BigDecimal(usedCodes), 2, RoundingMode.HALF_UP);
            overview.setAverageUsagePerCode(averageUsage);
        } else {
            overview.setAverageUsagePerCode(BigDecimal.ZERO);
        }
        
        // 计算重复使用率
        if (usedCodes > 0) {
            int repeatUsedCodes = (int) allCodes.stream()
                .filter(code -> code.getCurrentUseCount() != null && code.getCurrentUseCount() > 1)
                .count();
            BigDecimal repeatUsageRate = new BigDecimal(repeatUsedCodes)
                .divide(new BigDecimal(usedCodes), 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal(100));
            overview.setRepeatUsageRate(repeatUsageRate);
        } else {
            overview.setRepeatUsageRate(BigDecimal.ZERO);
        }
        
        // 设置可重复使用配置
        VoucherBatchOverviewResp.RepeatableSettings settings = new VoucherBatchOverviewResp.RepeatableSettings();
        settings.setMaxUseCount(batchConfig.getMaxUseCount());
        settings.setMaxUsePerUser(batchConfig.getMaxUsePerUser());
        settings.setUseIntervalHours(batchConfig.getUseIntervalHours());
        overview.setRepeatableSettings(settings);
        
        return overview;
    }

    @Override
    public VoucherInfo getBestVoucher(Long faceId, Long scenicId, DiscountDetectionContext context) {
        List<VoucherInfo> availableVouchers = getAvailableVouchers(faceId, scenicId);
        if (availableVouchers.isEmpty()) {
            return null;
        }
        
        // 计算每个券码的优惠金额，选择最优的
        VoucherInfo bestVoucher = null;
        BigDecimal maxDiscount = BigDecimal.ZERO;
        
        for (VoucherInfo voucher : availableVouchers) {
            BigDecimal discount = calculateVoucherDiscount(voucher, context);
            voucher.setActualDiscountAmount(discount);
            
            if (discount.compareTo(maxDiscount) > 0) {
                maxDiscount = discount;
                bestVoucher = voucher;
            }
        }
        
        return bestVoucher;
    }
    
    /**
     * 统一检查用户券码使用权限
     * 
     * @param voucherCode 券码实体
     * @param batchConfig 批次配置
     * @param faceId 用户faceId
     * @param isClaimed 是否为已领取状态（true=已领取，检查具体券码权限；false=未领取，检查批次权限）
     * @return 不可用原因，null表示可用
     */
    private String checkUserUsagePermission(PriceVoucherCode voucherCode, PriceVoucherBatchConfig batchConfig, Long faceId, boolean isClaimed) {
        if (faceId == null) {
            return "用户信息缺失";
        }
        
        // 1. 检查券码使用次数限制（仅针对已领取的券码）
        if (isClaimed) {
            Integer maxUseCount = batchConfig.getMaxUseCount();
            Integer currentUseCount = voucherCode.getCurrentUseCount() != null ? voucherCode.getCurrentUseCount() : 0;
            
            if (maxUseCount != null && currentUseCount >= maxUseCount) {
                return "券码使用次数已达上限";
            }
        }
        
        // 2. 检查用户使用次数限制
        Integer maxUsePerUser = batchConfig.getMaxUsePerUser();
        if (maxUsePerUser != null) {
            Integer userUseCount;
            if (isClaimed) {
                // 已领取：检查用户对该具体券码的使用次数
                userUseCount = usageRecordMapper.countByFaceIdAndVoucherCodeId(faceId, voucherCode.getId());
                if (userUseCount >= maxUsePerUser) {
                    return "您使用该券码的次数已达上限";
                }
            } else {
                // 未领取：检查用户在该批次下的总使用次数
                userUseCount = usageRecordMapper.countByFaceIdAndBatchId(faceId, batchConfig.getId());
                if (userUseCount >= maxUsePerUser) {
                    return "您在该批次下使用券码的次数已达上限";
                }
            }
        }
        
        // 3. 检查使用间隔时间限制
        Integer useIntervalHours = batchConfig.getUseIntervalHours();
        if (useIntervalHours != null) {
            Date lastUseTime;
            if (isClaimed) {
                // 已领取：检查该券码的最后使用时间
                lastUseTime = usageRecordMapper.getLastUseTimeByFaceIdAndVoucherCodeId(faceId, voucherCode.getId());
                if (lastUseTime != null) {
                    long diffMillis = System.currentTimeMillis() - lastUseTime.getTime();
                    long diffHours = TimeUnit.MILLISECONDS.toHours(diffMillis);
                    if (diffHours < useIntervalHours) {
                        return String.format("请等待%d小时后再次使用该券码", useIntervalHours - diffHours);
                    }
                }
            } else {
                // 未领取：检查该批次下的最后使用时间
                lastUseTime = usageRecordMapper.getLastUseTimeByFaceIdAndBatchId(faceId, batchConfig.getId());
                if (lastUseTime != null) {
                    long diffMillis = System.currentTimeMillis() - lastUseTime.getTime();
                    long diffHours = TimeUnit.MILLISECONDS.toHours(diffMillis);
                    if (diffHours < useIntervalHours) {
                        return String.format("请等待%d小时后再次使用该批次券码", useIntervalHours - diffHours);
                    }
                }
            }
        }
        
        return null; // 可用
    }
    
    /**
     * 构建券码信息DTO
     */
    private VoucherInfo buildVoucherInfo(PriceVoucherCode voucherCode, PriceVoucherBatchConfig batchConfig) {
        VoucherInfo voucherInfo = new VoucherInfo();
        voucherInfo.setVoucherId(voucherCode.getId());
        voucherInfo.setVoucherCode(voucherCode.getCode());
        voucherInfo.setBatchId(batchConfig.getId());
        voucherInfo.setBatchName(batchConfig.getBatchName());
        voucherInfo.setScenicId(voucherCode.getScenicId());
        voucherInfo.setBrokerId(batchConfig.getBrokerId());
        voucherInfo.setDiscountType(VoucherDiscountType.getByCode(batchConfig.getDiscountType()));
        voucherInfo.setDiscountValue(batchConfig.getDiscountValue());
        voucherInfo.setStatus(voucherCode.getStatus());
        voucherInfo.setClaimedTime(voucherCode.getClaimedTime());
        voucherInfo.setUsedTime(voucherCode.getUsedTime());
        voucherInfo.setApplicableProducts(batchConfig.getApplicableProducts());
        
        // 设置可重复使用相关信息
        Integer currentUseCount = voucherCode.getCurrentUseCount() != null ? voucherCode.getCurrentUseCount() : 0;
        voucherInfo.setCurrentUseCount(currentUseCount);
        voucherInfo.setMaxUseCount(batchConfig.getMaxUseCount());
        voucherInfo.setMaxUsePerUser(batchConfig.getMaxUsePerUser());
        voucherInfo.setUseIntervalHours(batchConfig.getUseIntervalHours());
        voucherInfo.setLastUsedTime(voucherCode.getLastUsedTime());
        
        // 设置时间范围信息
        voucherInfo.setValidStartTime(batchConfig.getValidStartTime());
        voucherInfo.setValidEndTime(batchConfig.getValidEndTime());
        
        // 计算剩余可使用次数
        if (batchConfig.getMaxUseCount() != null) {
            int remaining = batchConfig.getMaxUseCount() - currentUseCount;
            voucherInfo.setRemainingUseCount(Math.max(0, remaining));
        } else {
            voucherInfo.setRemainingUseCount(null); // 无限次
        }
        
        // 计算是否还能使用
        boolean canUseMore = true;
        if (batchConfig.getMaxUseCount() != null) {
            canUseMore = currentUseCount < batchConfig.getMaxUseCount();
        }
        voucherInfo.setCanUseMore(canUseMore);
        
        return voucherInfo;
    }
    
    /**
     * 筛选适用的商品
     */
    private List<ProductItem> filterApplicableProducts(List<ProductItem> products, List<ProductType> applicableProducts) {
        if (applicableProducts == null || applicableProducts.isEmpty()) {
            // null或空列表表示适用所有商品类型
            return products;
        }
        
        return products.stream()
                .filter(product -> {
                    try {
                        return applicableProducts.contains(product.getProductType());
                    } catch (IllegalArgumentException e) {
                        log.warn("未知的商品类型: {}", product.getProductType());
                        return false;
                    }
                })
                .collect(Collectors.toList());
    }
    
    /**
     * 计算适用商品的总金额
     */
    private BigDecimal calculateApplicableAmount(List<ProductItem> applicableItems, DiscountDetectionContext context) {
        // 简单计算：基于商品数量和单价
        // 在实际应用中可能需要更复杂的计算逻辑
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (ProductItem item : applicableItems) {
            BigDecimal itemAmount = item.getUnitPrice().multiply(BigDecimal.valueOf(item.getPurchaseCount()));
            totalAmount = totalAmount.add(itemAmount);
        }
        return totalAmount;
    }
}