package com.lesingle.edu.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lesingle.edu.common.enums.CourseStatus;
import com.lesingle.edu.common.enums.TenantPackageStatus;
import com.lesingle.edu.common.exception.BusinessException;
import com.lesingle.edu.dto.response.CourseCollectionResponse;
import com.lesingle.edu.dto.response.CoursePackageResponse;
import com.lesingle.edu.dto.response.PackageFilterMetaResponse;
import com.lesingle.edu.entity.*;
import com.lesingle.edu.mapper.*;
import com.lesingle.edu.service.CourseCollectionService;
import com.lesingle.edu.service.CourseLessonService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 课程套餐服务实现类（两层结构 - 最上层）
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CourseCollectionServiceImpl extends ServiceImpl<CourseCollectionMapper, CourseCollection> implements CourseCollectionService {

    private final CourseCollectionMapper collectionMapper;
    private final CourseCollectionPackageMapper collectionPackageMapper;
    private final CoursePackageMapper packageMapper;
    private final TenantPackageMapper tenantPackageMapper;
    private final CoursePackageCourseMapper packageCoursePackageMapper;
    private final CourseLessonService courseLessonService;
    private final ThemeMapper themeMapper;

    /**
     * 查询租户的课程套餐列表
     */
    @Override
    public List<CourseCollectionResponse> findTenantCollections(Long tenantId) {
        log.info("查询租户课程套餐，tenantId={}", tenantId);

        // 查询租户的课程套餐关联
        List<TenantPackage> tenantPackages = tenantPackageMapper.selectList(
                new LambdaQueryWrapper<TenantPackage>()
                        .eq(TenantPackage::getTenantId, tenantId)
                        .eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE.getCode())
                        .isNotNull(TenantPackage::getCollectionId)
                        .orderByDesc(TenantPackage::getCreatedAt)
        );

        log.info("查询到{}条租户套餐关联记录", tenantPackages.size());
        for (TenantPackage tp : tenantPackages) {
            log.info("  - collection_id: {}, start_date: {}, end_date: {}",
                tp.getCollectionId(), tp.getStartDate(), tp.getEndDate());
        }

        // 获取套餐详情并转换为响应对象
        List<CourseCollectionResponse> result = tenantPackages.stream()
                .map(tp -> {
                    CourseCollection collection = collectionMapper.selectById(tp.getCollectionId());
                    if (collection == null) {
                        log.warn("套餐不存在，collection_id={}", tp.getCollectionId());
                        return null;
                    }
                    // 过滤下架状态的课程套餐
                    if (CourseStatus.ARCHIVED.getCode().equals(collection.getStatus())) {
                        log.warn("套餐已下架，collection_id={}", tp.getCollectionId());
                        return null;
                    }
                    log.info("返回套餐：id={}, name={}, package_count={}",
                        collection.getId(), collection.getName(), collection.getPackageCount());
                    CourseCollectionResponse response = toResponse(collection);
                    // 设置租户套餐的额外信息（如果有）
                    response.setStartDate(tp.getStartDate());
                    response.setEndDate(tp.getEndDate());
                    return response;
                })
                .filter(r -> r != null)
                .collect(Collectors.toList());

        log.info("查询到{}个课程套餐", result.size());
        return result;
    }

    /**
     * 获取课程套餐详情（包含课程包列表）
     */
    @Override
    public CourseCollectionResponse getCollectionDetail(Long collectionId) {
        log.info("获取课程套餐详情，collectionId={}", collectionId);

        CourseCollection collection = collectionMapper.selectById(collectionId);
        if (collection == null) {
            log.warn("课程套餐不存在，collectionId={}", collectionId);
            return null;
        }

        return toResponse(collection);
    }

    /**
     * 分页查询课程套餐
     */
    @Override
    public Page<CourseCollectionResponse> pageCollections(Integer pageNum, Integer pageSize, String status, String gradeLevels) {
        log.info("分页查询课程套餐，pageNum={}, pageSize={}, status={}, gradeLevels={}", pageNum, pageSize, status, gradeLevels);

        LambdaQueryWrapper<CourseCollection> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(status)) {
            wrapper.eq(CourseCollection::getStatus, status);
        }
        // 年级筛选：gradeLevels 为逗号分隔的字符串，如 "小班，中班，大班"
        // 数据库存储为 JSON 数组 ["小班","中班"]，需要使用 JSON_CONTAINS 匹配
        // 多选年级应该是 OR 关系（包含任意一个所选年级即可）
        if (StringUtils.hasText(gradeLevels)) {
            String[] selectedGrades = gradeLevels.split(",");
            wrapper.and(w -> {
                for (int i = 0; i < selectedGrades.length; i++) {
                    String grade = selectedGrades[i].trim();
                    if (StringUtils.hasText(grade)) {
                        if (i == 0) {
                            w.apply("JSON_CONTAINS(grade_levels, ?)", "\"" + grade + "\"");
                        } else {
                            w.or().apply("JSON_CONTAINS(grade_levels, ?)", "\"" + grade + "\"");
                        }
                    }
                }
            });
        }
        wrapper.orderByDesc(CourseCollection::getCreatedAt);

        Page<CourseCollection> page = collectionMapper.selectPage(
                new Page<>(pageNum, pageSize),
                wrapper
        );

        // 转换为响应对象
        List<CourseCollectionResponse> responses = page.getRecords().stream()
                .map(this::toResponse)
                .collect(Collectors.toList());

        Page<CourseCollectionResponse> result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        result.setRecords(responses);
        return result;
    }

    /**
     * 获取课程套餐下的课程包列表
     */
    @Override
    public List<CoursePackageResponse> getPackagesByCollection(Long collectionId) {
        log.info("获取课程套餐的课程包列表，collectionId={}", collectionId);

        // 查询关联关系
        List<CourseCollectionPackage> associations = collectionPackageMapper.selectList(
                new LambdaQueryWrapper<CourseCollectionPackage>()
                        .eq(CourseCollectionPackage::getCollectionId, collectionId)
                        .orderByAsc(CourseCollectionPackage::getSortOrder)
        );

        if (associations.isEmpty()) {
            return new ArrayList<>();
        }

        // 获取课程包详情
        List<Long> packageIds = associations.stream()
                .map(CourseCollectionPackage::getPackageId)
                .collect(Collectors.toList());

        List<CoursePackage> packages = packageMapper.selectList(
                new LambdaQueryWrapper<CoursePackage>()
                        .in(CoursePackage::getId, packageIds)
                        .eq(CoursePackage::getStatus, CourseStatus.PUBLISHED.getCode())
        );

        // 转换为响应对象并设置排序号
        List<CoursePackageResponse> result = packages.stream()
                .map(pkg -> {
                    CoursePackageResponse response = toPackageResponse(pkg);
                    // 设置排序号
                    associations.stream()
                            .filter(a -> a.getPackageId().equals(pkg.getId()))
                            .findFirst()
                            .ifPresent(a -> response.setSortOrder(a.getSortOrder()));
                    return response;
                })
                .collect(Collectors.toList());

        enrichCoursePackageThemeFields(packages, result);

        log.info("查询到{}个课程包", result.size());
        return result;
    }

    /**
     * 获取课程套餐下的课程包列表（支持筛选）
     */
    @Override
    public List<CoursePackageResponse> getPackagesByCollection(Long collectionId, String grade, String lessonType, Long themeId, String keyword) {
        log.info("获取课程套餐的课程包列表（筛选），collectionId={}, grade={}, lessonType={}, themeId={}, keyword={}", collectionId, grade, lessonType, themeId, keyword);

        // 查询关联关系
        List<CourseCollectionPackage> associations = collectionPackageMapper.selectList(
                new LambdaQueryWrapper<CourseCollectionPackage>()
                        .eq(CourseCollectionPackage::getCollectionId, collectionId)
                        .orderByAsc(CourseCollectionPackage::getSortOrder)
        );

        if (associations.isEmpty()) {
            return new ArrayList<>();
        }

        // 获取课程包ID列表
        List<Long> packageIds = associations.stream()
                .map(CourseCollectionPackage::getPackageId)
                .collect(Collectors.toList());

        // 课程配置筛选：仅保留包含该课程环节类型的课程包
        if (StringUtils.hasText(lessonType)) {
            List<Long> idsWithLesson = courseLessonService.findCourseIdsByLessonType(lessonType);
            Set<Long> idSet = new HashSet<>(idsWithLesson);
            packageIds = packageIds.stream().filter(idSet::contains).collect(Collectors.toList());
            if (packageIds.isEmpty()) {
                return new ArrayList<>();
            }
        }

        // 构建查询条件
        LambdaQueryWrapper<CoursePackage> wrapper = new LambdaQueryWrapper<CoursePackage>()
                .in(CoursePackage::getId, packageIds)
                .eq(CoursePackage::getStatus, CourseStatus.PUBLISHED.getCode());

        // 年级筛选：gradeTags 是 JSON 数组格式
        if (StringUtils.hasText(grade)) {
            wrapper.apply("JSON_CONTAINS(grade_tags, {0})", "\"" + grade + "\"");
        }

        // 课程包主题筛选
        if (themeId != null) {
            wrapper.eq(CoursePackage::getThemeId, themeId);
        }

        // 关键词搜索
        if (StringUtils.hasText(keyword)) {
            wrapper.and(w -> w
                    .like(CoursePackage::getName, keyword)
                    .or()
                    .like(CoursePackage::getPictureBookName, keyword)
            );
        }

        List<CoursePackage> packages = packageMapper.selectList(wrapper);

        // 获取所有主题信息（批量查询优化）
        Set<Long> themeIds = packages.stream()
                .map(CoursePackage::getThemeId)
                .filter(id -> id != null)
                .collect(Collectors.toSet());
        Map<Long, Theme> themeEntityMap = new HashMap<>();
        if (!themeIds.isEmpty()) {
            List<Theme> themes = themeMapper.selectBatchIds(themeIds);
            themeEntityMap = themes.stream()
                    .collect(Collectors.toMap(Theme::getId, t -> t));
        }

        // 转换为响应对象
        final Map<Long, Theme> finalThemeMap = themeEntityMap;
        List<CoursePackageResponse> result = packages.stream()
                .map(pkg -> {
                    CoursePackageResponse response = toPackageResponse(pkg);
                    // 设置主题名称与颜色
                    if (pkg.getThemeId() != null) {
                        response.setThemeId(pkg.getThemeId());
                        Theme t = finalThemeMap.get(pkg.getThemeId());
                        if (t != null) {
                            response.setThemeName(t.getName());
                            response.setThemeColor(t.getColor());
                        }
                    }
                    // 设置排序号
                    associations.stream()
                            .filter(a -> a.getPackageId().equals(pkg.getId()))
                            .findFirst()
                            .ifPresent(a -> response.setSortOrder(a.getSortOrder()));
                    return response;
                })
                .collect(Collectors.toList());

        log.info("筛选后查询到{}个课程包", result.size());
        return result;
    }

    /**
     * 获取套餐的筛选元数据
     */
    @Override
    public PackageFilterMetaResponse getPackageFilterMeta(Long collectionId) {
        log.info("获取套餐筛选元数据，collectionId={}", collectionId);

        // 查询套餐下所有课程包
        List<CourseCollectionPackage> associations = collectionPackageMapper.selectList(
                new LambdaQueryWrapper<CourseCollectionPackage>()
                        .eq(CourseCollectionPackage::getCollectionId, collectionId)
        );

        if (associations.isEmpty()) {
            return PackageFilterMetaResponse.builder()
                    .grades(new ArrayList<>())
                    .lessonTypes(new ArrayList<>())
                    .themes(new ArrayList<>())
                    .build();
        }

        List<Long> packageIds = associations.stream()
                .map(CourseCollectionPackage::getPackageId)
                .collect(Collectors.toList());

        List<CoursePackage> packages = packageMapper.selectList(
                new LambdaQueryWrapper<CoursePackage>()
                        .in(CoursePackage::getId, packageIds)
                        .eq(CoursePackage::getStatus, CourseStatus.PUBLISHED.getCode())
        );

        // 统计年级分布
        Map<String, Integer> gradeCountMap = new HashMap<>();
        for (CoursePackage pkg : packages) {
            String[] grades = parseGradeTags(pkg.getGradeTags());
            for (String g : grades) {
                gradeCountMap.merge(g, 1, Integer::sum);
            }
        }

        // 按顺序生成年级选项
        List<String> gradeOrder = List.of("小班", "中班", "大班");
        List<PackageFilterMetaResponse.GradeOption> grades = gradeOrder.stream()
                .filter(gradeCountMap::containsKey)
                .map(grade -> PackageFilterMetaResponse.GradeOption.builder()
                        .label(grade)
                        .count(gradeCountMap.get(grade))
                        .build())
                .collect(Collectors.toList());

        // 统计课程配置（课程环节类型）分布：查询所有课程环节，按规范化类型统计课程包数量
        List<CourseLesson> allLessons = courseLessonService.list(
                new LambdaQueryWrapper<CourseLesson>()
                        .in(CourseLesson::getCourseId, packageIds)
                        .select(CourseLesson::getCourseId, CourseLesson::getLessonType)
        );
        // 规范化类型 -> 包含该类型的课程包ID集合
        Map<String, Set<Long>> typeToPackageIds = new HashMap<>();
        for (CourseLesson lesson : allLessons) {
            String canonical = normalizeLessonTypeForFilter(lesson.getLessonType());
            if (canonical != null) {
                typeToPackageIds.computeIfAbsent(canonical, k -> new HashSet<>()).add(lesson.getCourseId());
            }
        }
        // 按固定顺序生成课程配置选项（与管理端一致）
        List<String> lessonTypeOrder = List.of("INTRODUCTION", "COLLECTIVE", "HEALTH", "LANGUAGE", "SCIENCE", "SOCIAL", "ART");
        Map<String, String> typeToName = getLessonTypeDisplayNames();
        List<PackageFilterMetaResponse.LessonTypeOption> lessonTypes = lessonTypeOrder.stream()
                .filter(typeToPackageIds::containsKey)
                .map(type -> PackageFilterMetaResponse.LessonTypeOption.builder()
                        .lessonType(type)
                        .name(typeToName.getOrDefault(type, type))
                        .count(typeToPackageIds.get(type).size())
                        .build())
                .collect(Collectors.toList());

        // 统计课程包主题分布
        Map<Long, Integer> themeCountMap = new HashMap<>();
        Map<Long, String> themeNameMap = new HashMap<>();
        for (CoursePackage pkg : packages) {
            Long tid = pkg.getThemeId();
            if (tid != null) {
                themeCountMap.merge(tid, 1, Integer::sum);
                if (!themeNameMap.containsKey(tid)) {
                    Theme theme = themeMapper.selectById(tid);
                    themeNameMap.put(tid, theme != null ? theme.getName() : "主题" + tid);
                }
            }
        }
        List<PackageFilterMetaResponse.ThemeOption> themes = themeCountMap.entrySet().stream()
                .map(e -> PackageFilterMetaResponse.ThemeOption.builder()
                        .themeId(e.getKey())
                        .name(themeNameMap.getOrDefault(e.getKey(), ""))
                        .count(e.getValue())
                        .build())
                .sorted((a, b) -> themeNameMap.getOrDefault(a.getThemeId(), "").compareTo(themeNameMap.getOrDefault(b.getThemeId(), "")))
                .collect(Collectors.toList());

        return PackageFilterMetaResponse.builder()
                .grades(grades)
                .lessonTypes(lessonTypes)
                .themes(themes)
                .build();
    }

    /**
     * 将课程环节类型规范化为筛选用的标准编码（与管理端、前端 LESSON_TYPE_NAMES 一致）
     */
    private String normalizeLessonTypeForFilter(String lessonType) {
        if (!StringUtils.hasText(lessonType)) return null;
        return switch (lessonType.toUpperCase()) {
            case "INTRODUCTION", "INTRO" -> "INTRODUCTION";
            case "COLLECTIVE" -> "COLLECTIVE";
            case "LANGUAGE", "DOMAIN_LANGUAGE" -> "LANGUAGE";
            case "HEALTH", "DOMAIN_HEALTH" -> "HEALTH";
            case "SCIENCE", "DOMAIN_SCIENCE" -> "SCIENCE";
            case "SOCIAL", "SOCIETY", "DOMAIN_SOCIAL" -> "SOCIAL";
            case "ART", "DOMAIN_ART" -> "ART";
            default -> null;
        };
    }

    /**
     * 课程类型编码 -> 中文名称（与管理端、前端 tagMaps 一致）
     */
    private Map<String, String> getLessonTypeDisplayNames() {
        Map<String, String> m = new HashMap<>();
        m.put("INTRODUCTION", "导入课");
        m.put("COLLECTIVE", "集体课");
        m.put("LANGUAGE", "语言");
        m.put("HEALTH", "健康");
        m.put("SCIENCE", "科学");
        m.put("SOCIAL", "社会");
        m.put("ART", "艺术");
        return m;
    }

    /**
     * 解析年级标签
     */
    private String[] parseGradeTags(String gradeTags) {
        if (!StringUtils.hasText(gradeTags)) {
            return new String[0];
        }
        try {
            if (gradeTags.trim().startsWith("[")) {
                return JSON.parseArray(gradeTags, String.class).toArray(new String[0]);
            }
            return gradeTags.split(",");
        } catch (Exception e) {
            return new String[0];
        }
    }

    /**
     * 创建课程套餐
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CourseCollectionResponse createCollection(String name, String description, Long price,
                                              Long discountPrice, String discountType, String[] gradeLevels) {
        log.info("创建课程套餐，name={}, price={}, discountPrice={}, discountType={}", name, price, discountPrice, discountType);

        // 校验价格不能为负
        if (price == null || price < 0) {
            throw new BusinessException("价格不能为空或负数");
        }

        // 校验折扣价格逻辑
        if (discountPrice != null) {
            if ("PERCENTAGE".equals(discountType)) {
                // 折扣类型：折扣率应该是 0-10000 之间（支持两位小数，如 99.99%）
                if (discountPrice < 0 || discountPrice > 10000) {
                    throw new BusinessException("折扣率应该在 0-10000 分之间（0-100%）");
                }
            } else if ("FIXED".equals(discountType)) {
                // 立减类型：立减金额不能超过原价
                if (discountPrice > price) {
                    throw new BusinessException("立减金额不能超过原价");
                }
            }
        }

        CourseCollection collection = new CourseCollection();
        collection.setName(name);
        collection.setDescription(description);
        collection.setPrice(price);
        collection.setDiscountPrice(discountPrice);
        collection.setDiscountType(discountType);
        // 将数组转为 JSON 字符串存储到 JSON 字段
        collection.setGradeLevels(JSON.toJSONString(gradeLevels));
        collection.setPackageCount(0);
        collection.setStatus(CourseStatus.DRAFT.getCode());

        collectionMapper.insert(collection);

        log.info("课程套餐创建成功，id={}", collection.getId());
        return toResponse(collection);
    }

    /**
     * 设置课程套餐的课程包
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setCollectionPackages(Long collectionId, List<Long> packageIds) {
        log.info("设置课程套餐的课程包，collectionId={}, packageCount={}", collectionId, packageIds.size());

        // 验证课程套餐是否存在
        CourseCollection collection = collectionMapper.selectById(collectionId);
        if (collection == null) {
            throw new BusinessException("课程套餐不存在");
        }

        // 去重：保持首次出现顺序，避免 uk_collection_package 唯一约束冲突
        List<Long> distinctIds = packageIds.stream().distinct().collect(Collectors.toList());

        // 验证课程包是否存在（应用层外键约束）
        if (!distinctIds.isEmpty()) {
            List<CoursePackage> packages = packageMapper.selectList(
                    new LambdaQueryWrapper<CoursePackage>()
                            .in(CoursePackage::getId, distinctIds)
            );
            if (packages.size() != distinctIds.size()) {
                throw new BusinessException("存在无效的课程包 ID");
            }
        }

        // 删除旧的关联
        collectionPackageMapper.delete(
                new LambdaQueryWrapper<CourseCollectionPackage>()
                        .eq(CourseCollectionPackage::getCollectionId, collectionId)
        );

        // 创建新的关联（在事务内顺序插入）
        for (int i = 0; i < distinctIds.size(); i++) {
            CourseCollectionPackage association = new CourseCollectionPackage();
            association.setCollectionId(collectionId);
            association.setPackageId(distinctIds.get(i));
            association.setSortOrder(i + 1);
            collectionPackageMapper.insert(association);
        }

        // 更新课程包数量（复用前面已验证的 collection 变量）
        collection.setPackageCount(distinctIds.size());
        collectionMapper.updateById(collection);

        log.info("课程套餐的课程包设置完成");
    }

    /**
     * 更新课程套餐
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CourseCollectionResponse updateCollection(Long id, String name, String description, Long price,
                                              Long discountPrice, String discountType, String[] gradeLevels) {
        log.info("更新课程套餐，id={}, name={}, price={}, discountPrice={}, discountType={}", id, name, price, discountPrice, discountType);

        CourseCollection collection = collectionMapper.selectById(id);
        if (collection == null) {
            throw new IllegalArgumentException("课程套餐不存在");
        }

        // 校验价格不能为负
        if (price == null || price < 0) {
            throw new BusinessException("价格不能为空或负数");
        }

        // 校验折扣价格逻辑
        if (discountPrice != null) {
            if ("PERCENTAGE".equals(discountType)) {
                // 折扣类型：折扣率应该是 0-10000 之间（支持两位小数，如 99.99%）
                if (discountPrice < 0 || discountPrice > 10000) {
                    throw new BusinessException("折扣率应该在 0-10000 分之间（0-100%）");
                }
            } else if ("FIXED".equals(discountType)) {
                // 立减类型：立减金额不能超过原价
                if (discountPrice > price) {
                    throw new BusinessException("立减金额不能超过原价");
                }
            }
        }

        collection.setName(name);
        collection.setDescription(description);
        collection.setPrice(price);
        collection.setDiscountPrice(discountPrice);
        collection.setDiscountType(discountType);
        // 将数组转为 JSON 字符串存储到 JSON 字段
        collection.setGradeLevels(JSON.toJSONString(gradeLevels));

        collectionMapper.updateById(collection);

        log.info("课程套餐更新成功，id={}", id);
        return toResponse(collection);
    }

    /**
     * 删除课程套餐
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCollection(Long id) {
        log.info("删除课程套餐，id={}", id);

        // 检查是否有租户正在使用此课程套餐
        Long tenantCount = tenantPackageMapper.selectCount(
                new LambdaQueryWrapper<TenantPackage>()
                        .eq(TenantPackage::getCollectionId, id)
                        .eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
        );

        if (tenantCount > 0) {
            log.warn("删除课程套餐失败，有 {} 个租户正在使用此套餐，id={}", tenantCount, id);
            throw new BusinessException("有 " + tenantCount + " 个租户正在使用此课程套餐，无法删除");
        }

        // 清理所有状态的租户套餐关联记录（包括非活跃状态）
        List<TenantPackage> allTenantPackages = tenantPackageMapper.selectList(
                new LambdaQueryWrapper<TenantPackage>()
                        .eq(TenantPackage::getCollectionId, id)
        );

        if (!allTenantPackages.isEmpty()) {
            tenantPackageMapper.delete(
                    new LambdaQueryWrapper<TenantPackage>()
                            .eq(TenantPackage::getCollectionId, id)
            );
            log.info("已清理 {} 条租户套餐关联记录", allTenantPackages.size());
        }

        // 删除课程套餐与课程包的关联关系
        List<CourseCollectionPackage> collectionPackages = collectionPackageMapper.selectList(
                new LambdaQueryWrapper<CourseCollectionPackage>()
                        .eq(CourseCollectionPackage::getCollectionId, id)
        );

        if (!collectionPackages.isEmpty()) {
            collectionPackageMapper.delete(
                    new LambdaQueryWrapper<CourseCollectionPackage>()
                            .eq(CourseCollectionPackage::getCollectionId, id)
            );
            log.info("已清理 {} 条课程包关联记录", collectionPackages.size());
        }

        // 删除课程套餐
        collectionMapper.deleteById(id);

        log.info("课程套餐删除成功，id={}", id);
    }

    /**
     * 发布课程套餐
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publishCollection(Long id) {
        log.info("发布课程套餐，id={}", id);

        CourseCollection collection = collectionMapper.selectById(id);
        if (collection == null) {
            throw new IllegalArgumentException("课程套餐不存在");
        }

        collection.setStatus(CourseStatus.PUBLISHED.getCode());
        collection.setPublishedAt(LocalDateTime.now());
        collectionMapper.updateById(collection);

        log.info("课程套餐发布成功，id={}", id);
    }

    /**
     * 下架课程套餐
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void archiveCollection(Long id) {
        log.info("下架课程套餐，id={}", id);

        CourseCollection collection = collectionMapper.selectById(id);
        if (collection == null) {
            throw new IllegalArgumentException("课程套餐不存在");
        }

        // 检查是否有租户正在使用此套餐
        Long tenantCount = tenantPackageMapper.selectCount(
                new LambdaQueryWrapper<TenantPackage>()
                        .eq(TenantPackage::getCollectionId, id)
                        .eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
        );

        if (tenantCount > 0) {
            log.warn("下架课程套餐失败，有 {} 个租户正在使用此套餐，id={}", tenantCount, id);
            throw new BusinessException("该套餐正在被 " + tenantCount + " 个租户使用，无法下架");
        }

        collection.setStatus(CourseStatus.ARCHIVED.getCode());
        collectionMapper.updateById(collection);

        log.info("课程套餐下架成功，id={}", id);
    }

    /**
     * 重新发布课程套餐
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void republishCollection(Long id) {
        log.info("重新发布课程套餐，id={}", id);

        CourseCollection collection = collectionMapper.selectById(id);
        if (collection == null) {
            throw new IllegalArgumentException("课程套餐不存在");
        }

        collection.setStatus(CourseStatus.PUBLISHED.getCode());
        collection.setPublishedAt(LocalDateTime.now());
        collectionMapper.updateById(collection);

        log.info("课程套餐重新发布成功，id={}", id);
    }

    /**
     * 撤销审核
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdrawCollection(Long id) {
        log.info("撤销课程套餐审核，id={}", id);

        CourseCollection collection = collectionMapper.selectById(id);
        if (collection == null) {
            throw new IllegalArgumentException("课程套餐不存在");
        }

        collection.setStatus(CourseStatus.DRAFT.getCode());
        collectionMapper.updateById(collection);

        log.info("课程套餐审核撤销成功，id={}", id);
    }

    /**
     * 提交课程套餐审核
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitCollection(Long id) {
        log.info("提交课程套餐审核，id={}", id);

        CourseCollection collection = collectionMapper.selectById(id);
        if (collection == null) {
            throw new IllegalArgumentException("课程套餐不存在");
        }

        // 检查是否包含课程包
        if (collection.getPackageCount() == null || collection.getPackageCount() == 0) {
            throw new BusinessException("课程套餐必须包含至少一个课程包");
        }

        collection.setStatus(CourseStatus.PENDING.getCode());
        collection.setSubmittedAt(LocalDateTime.now());
        collectionMapper.updateById(collection);

        log.info("课程套餐提交审核成功，id={}", id);
    }

    /**
     * 审核驳回课程套餐
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rejectCollection(Long id, String comment) {
        log.info("审核驳回课程套餐，id={}, comment={}", id, comment);

        CourseCollection collection = collectionMapper.selectById(id);
        if (collection == null) {
            throw new IllegalArgumentException("课程套餐不存在");
        }

        collection.setStatus(CourseStatus.REJECTED.getCode());
        collection.setReviewedAt(LocalDateTime.now());
        collection.setReviewComment(comment);
        collectionMapper.updateById(collection);

        log.info("课程套餐审核驳回成功，id={}", id);
    }

    /**
     * 续费租户课程套餐
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void renewTenantCollection(Long tenantId, Long collectionId, java.time.LocalDate endDate, Long pricePaid) {
        log.info("续费租户课程套餐，tenantId={}, collectionId={}, endDate={}, pricePaid={}", tenantId, collectionId, endDate, pricePaid);

        // 查询现有租户套餐关联
        List<TenantPackage> existingPackages = tenantPackageMapper.selectList(
                new LambdaQueryWrapper<TenantPackage>()
                        .eq(TenantPackage::getTenantId, tenantId)
                        .eq(TenantPackage::getCollectionId, collectionId)
        );

        if (!existingPackages.isEmpty()) {
            // 更新现有记录
            TenantPackage existing = existingPackages.get(0);
            existing.setEndDate(endDate);
            existing.setStatus(TenantPackageStatus.ACTIVE);
            if (pricePaid != null) {
                existing.setPricePaid(pricePaid);
            }
            existing.setUpdatedAt(LocalDateTime.now());
            tenantPackageMapper.updateById(existing);
            log.info("租户课程套餐续费成功，tenantId={}, collectionId={}", tenantId, collectionId);
        } else {
            // 查询课程套餐信息
            CourseCollection collection = collectionMapper.selectById(collectionId);
            if (collection == null) {
                throw new IllegalArgumentException("课程套餐不存在");
            }

            // 创建新记录
            TenantPackage tp = new TenantPackage();
            tp.setTenantId(tenantId);
            tp.setCollectionId(collectionId);
            tp.setStartDate(java.time.LocalDate.now());
            tp.setEndDate(endDate);
            tp.setStatus(TenantPackageStatus.ACTIVE);
            tp.setPricePaid(pricePaid != null ? pricePaid :
                (collection.getDiscountPrice() != null ? collection.getDiscountPrice() : collection.getPrice()));
            tp.setCreatedAt(LocalDateTime.now());
            tenantPackageMapper.insert(tp);
            log.info("租户课程套餐新办成功，tenantId={}, collectionId={}", tenantId, collectionId);
        }
    }

    /**
     * 解析适用年级：数据库存储为 JSON 数组 ["小班","中班","大班"]，需正确解析
     */
    private String[] parseGradeLevels(String gradeLevels) {
        if (!StringUtils.hasText(gradeLevels)) {
            return new String[0];
        }
        try {
            if (gradeLevels.trim().startsWith("[")) {
                return JSON.parseArray(gradeLevels, String.class).toArray(new String[0]);
            }
            // 兼容旧数据：逗号分隔格式
            return gradeLevels.split(",");
        } catch (Exception e) {
            log.warn("解析 gradeLevels 失败：{}", gradeLevels, e);
            return new String[0];
        }
    }

    /**
     * 转换为响应对象
     */
    private CourseCollectionResponse toResponse(CourseCollection collection) {
        // 获取课程包列表
        List<CourseCollectionResponse.CoursePackageItem> packages = getPackagesByCollection(collection.getId()).stream()
                .map(pkg -> {
                    CourseCollectionResponse.CoursePackageItem item = new CourseCollectionResponse.CoursePackageItem();
                    item.setId(pkg.getId());
                    item.setName(pkg.getName());
                    item.setDescription(pkg.getDescription());
                    item.setGradeLevels(pkg.getGradeLevels() != null ? pkg.getGradeLevels() : new String[0]);
                    item.setCourseCount(pkg.getCourseCount() != null ? pkg.getCourseCount() : 0);
                    item.setSortOrder(pkg.getSortOrder());
                    return item;
                })
                .collect(Collectors.toList());

        return CourseCollectionResponse.builder()
                .id(collection.getId())
                .name(collection.getName())
                .description(collection.getDescription())
                .price(collection.getPrice())
                .discountPrice(collection.getDiscountPrice())
                .discountType(collection.getDiscountType())
                .gradeLevels(parseGradeLevels(collection.getGradeLevels()))
                .packageCount(collection.getPackageCount())
                .status(collection.getStatus())
                .submittedAt(collection.getSubmittedAt())
                .submittedBy(collection.getSubmittedBy())
                .reviewedAt(collection.getReviewedAt())
                .reviewedBy(collection.getReviewedBy())
                .reviewComment(collection.getReviewComment())
                .publishedAt(collection.getPublishedAt())
                .createdAt(collection.getCreatedAt())
                .updatedAt(collection.getUpdatedAt())
                .packages(packages)
                .build();
    }

    /**
     * 批量填充课程包的主题名称、颜色（与 theme 表一致）
     */
    private void enrichCoursePackageThemeFields(List<CoursePackage> packages, List<CoursePackageResponse> responses) {
        if (packages == null || responses == null || packages.size() != responses.size()) {
            return;
        }
        Set<Long> themeIds = packages.stream()
                .map(CoursePackage::getThemeId)
                .filter(id -> id != null)
                .collect(Collectors.toSet());
        if (themeIds.isEmpty()) {
            return;
        }
        List<Theme> themes = themeMapper.selectBatchIds(themeIds);
        Map<Long, Theme> themeMap = themes.stream()
                .collect(Collectors.toMap(Theme::getId, t -> t));
        for (int i = 0; i < packages.size(); i++) {
            CoursePackage pkg = packages.get(i);
            CoursePackageResponse resp = responses.get(i);
            if (pkg.getThemeId() == null) {
                continue;
            }
            Theme t = themeMap.get(pkg.getThemeId());
            if (t != null) {
                resp.setThemeName(t.getName());
                resp.setThemeColor(t.getColor());
            }
        }
    }

    /**
     * 转换为课程包响应对象（包含课程列表和排课计划参考）
     */
    private CoursePackageResponse toPackageResponse(CoursePackage pkg) {
        // 解析 gradeTags（CoursePackage 使用 gradeTags）
        String[] gradeLevelsArray = new String[0];
        if (pkg.getGradeTags() != null && !pkg.getGradeTags().isEmpty()) {
            try {
                // gradeTags 是 JSON 数组格式，尝试解析
                if (pkg.getGradeTags().startsWith("[")) {
                    gradeLevelsArray = com.alibaba.fastjson2.JSON.parseArray(pkg.getGradeTags(), String.class).toArray(new String[0]);
                } else {
                    gradeLevelsArray = pkg.getGradeTags().split(",");
                }
            } catch (Exception e) {
                gradeLevelsArray = new String[0];
            }
        }

        List<CoursePackageResponse.CoursePackageCourseItem> courseItems = new ArrayList<>();

        // 查询课程包关联的课程环节
        List<CourseLesson> lessons = courseLessonService.findByCourseId(pkg.getId());

        if (!lessons.isEmpty()) {
            courseItems = lessons.stream()
                    .map(lesson -> {
                        CoursePackageResponse.CoursePackageCourseItem item = new CoursePackageResponse.CoursePackageCourseItem();
                        item.setId(lesson.getId());
                        item.setName(lesson.getName());
                        item.setGradeLevel(null); // 课程环节没有年级字段
                        item.setSortOrder(lesson.getSortOrder());
                        item.setScheduleRefData(pkg.getScheduleRefData());
                        item.setLessonType(lesson.getLessonType());
                        return item;
                    })
                    .collect(Collectors.toList());
        }

        return CoursePackageResponse.builder()
                .id(pkg.getId())
                .name(pkg.getName())
                .description(pkg.getDescription())
                .price(null) // CoursePackage 没有价格字段
                .discountPrice(null)
                .discountType(null)
                .gradeLevels(gradeLevelsArray)
                .gradeTags(gradeLevelsArray) // 同时设置 gradeTags 字段，供前端使用
                .courseCount(lessons.size()) // 使用课程环节数量
                .status(pkg.getStatus())
                // 新增字段：封面、绘本、主题
                .coverImagePath(pkg.getCoverImagePath())
                .pictureBookName(pkg.getPictureBookName())
                .themeId(pkg.getThemeId())
                .durationMinutes(pkg.getDurationMinutes())
                .usageCount(pkg.getUsageCount())
                .avgRating(pkg.getAvgRating())
                // 审核相关
                .submittedAt(pkg.getSubmittedAt())
                .submittedBy(pkg.getSubmittedBy())
                .reviewedAt(pkg.getReviewedAt())
                .reviewedBy(pkg.getReviewedBy())
                .reviewComment(pkg.getReviewComment())
                .publishedAt(pkg.getPublishedAt())
                .createdAt(pkg.getCreatedAt())
                .updatedAt(pkg.getUpdatedAt())
                .courses(courseItems)
                .build();
    }
}
