package org.jeecg.modules.app.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.ObjectUtils;
import org.jeecg.modules.app.dto.GetPlaceListDTO;
import org.jeecg.modules.app.dto.SearchDTO;
import org.jeecg.modules.app.service.IAppHomeService;
import org.jeecg.modules.app.vo.*;
import org.jeecg.modules.system.app.entity.*;
import org.jeecg.modules.system.app.mapper.*;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.mapper.SysUserMapper;
import org.jeecg.modules.system.util.PositionUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static org.jeecg.common.constant.CommonConstant.INSTRUCTOR;

@Service
public class AppHomeServiceImpl implements IAppHomeService {
    @Resource
    private AppBannerMapper appBannerMapper;
    @Resource
    private AppCoursesMapper appCoursesMapper;
    @Resource
    private AppInstructorMapper appInstructorMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private AppSiteMapper appSiteMapper;
    @Resource
    private AppCategoryMapper appCategoryMapper;
    @Resource
    private AppGameMapper appGameMapper;
    @Resource
    private AppSitePlaceMapper appSitePlaceMapper;
    @Resource
    private AppSitePriceRulesMapper appSitePriceRulesMapper;
    @Resource
    private AppSearchHotMapper appSearchHotMapper;
    @Resource
    private AppGamePriceRulesMapper appGamePriceRulesMapper;
    @Resource
    private EvaluateMapper evaluateMapper;
    @Resource
    private AppOrderProInfoMapper appOrderProInfoMapper;

    @Override
    public HomeVO homeInfo() {
        // 获取 banners
        List<AppBanner> appBanners = appBannerMapper.selectList(Wrappers.<AppBanner>lambdaQuery()
                .eq(AppBanner::getDelFlag, 0).eq(AppBanner::getIsEnabled,1));

        // 精品课程（最多3个）
        List<AppCourses> appCoursesFine = appCoursesMapper.selectList(Wrappers.<AppCourses>lambdaQuery()
                .eq(AppCourses::getPriceType, 0).eq(AppCourses::getRackingStatus,0).gt(AppCourses::getEndTime, new Date()).last("LIMIT 3"));

        // 免费课程（最多3个）
        List<AppCourses> appCoursesFree = appCoursesMapper.selectList(Wrappers.<AppCourses>lambdaQuery()
                .eq(AppCourses::getPriceType, 1).eq(AppCourses::getRackingStatus,0).gt(AppCourses::getEndTime, new Date()).last("LIMIT 3"));

        // 合并课程信息
        List<CourseVO> courseVO = new ArrayList<>();
        courseVO.addAll(convertToCoureseVOList(appCoursesFine));
        courseVO.addAll(convertToCoureseVOList(appCoursesFree));

        // 获取好评率最高的两个教练 ID
        List<String> topInstructorUserIds = sysUserMapper.getUserIdListByRoleId(INSTRUCTOR).stream()
                .map(userId -> {
                    AppInstructor instructor = appInstructorMapper.selectOne(
                            Wrappers.<AppInstructor>lambdaQuery().eq(AppInstructor::getUserId, userId));
                    return new Object() {
                        final String id = userId;
                        final Integer orderSum = instructor != null ? getInstructorOrderNum(userId) : 0;
                    };
                })
                .sorted((a, b) -> Integer.compare(b.orderSum, a.orderSum))
                .limit(2)
                .map(obj -> obj.id)
                .collect(Collectors.toList());

        // 构建教练列表
        List<InstructorVO> instructorList = new ArrayList<>();
        for (String userId : topInstructorUserIds) {
            SysUser sysUser = sysUserMapper.selectById(userId);
            AppInstructor appInstructor = appInstructorMapper.selectOne(
                    Wrappers.<AppInstructor>lambdaQuery().eq(AppInstructor::getUserId, userId));

            InstructorVO instructorVO = new InstructorVO();
            BeanUtils.copyProperties(appInstructor,instructorVO);
            List<String> list = new ArrayList<>();
                    List.of(appInstructor.getTrainingPrograms().split(",")).forEach(item -> {
                        String str = appCategoryMapper.selectById(item).getName();
                        list.add(str);
                    });
            AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getOrgCode, appInstructor.getOrgCode()));
            if(null != appSite){
                instructorVO.setId(sysUser.getId())
                        .setAvatar(sysUser.getAvatar())
                        .setName(sysUser.getRealname()).setList(list)
                        .setTeachingCount(getInstructorTeachingNum(userId))
                        .setOrgName(appSite.getName());
                instructorVO.setOrderCount((long) getInstructorOrderNum(userId));
            }
            // 获取该教练的课程（最多取2个）
            List<AppCourses> courses = appCoursesMapper.selectList(
                    Wrappers.<AppCourses>lambdaQuery().like(AppCourses::getUserId, userId)
                            .eq(AppCourses::getRackingStatus,0)
                            .gt(AppCourses::getEndTime, new Date()).last("LIMIT 2"));
            List<InstructorVO.CourseInfoVO> courseInfoVOS = courses.stream()
                    .map(course -> {
                        InstructorVO.CourseInfoVO vo = new InstructorVO.CourseInfoVO();
                        BeanUtils.copyProperties(course,vo);
                        vo.setCount((long) getCourseSalesCount(course.getId()));
                        vo.setSellingPrice(course.getSellingPrice());
                        return vo;
                    })
                    .collect(Collectors.toList());

            instructorVO.setCourseList(courseInfoVOS);
            instructorList.add(instructorVO);
        }
        // 返回首页数据
        return new HomeVO()
                .setBannerList(appBanners.stream()
                        .map(banner -> new AppBannerVO()
                                .setId(banner.getId())
                                .setEventType(banner.getEventType())
                                .setEventValue(banner.getEventValue())
                                .setSortOrder(banner.getSortOrder())
                                .setImageUrl(banner.getImageUrl()))
                        .collect(Collectors.toList()))
                .setCourseList(courseVO)
                .setInstructorList(instructorList);
    }

    /**
     * @Author SheepHy
     * @Description 合并课程信息
     * @Date 9:14 2025/7/4
     * @Param appCoureseList {@link List<AppCourses>}
     * @return List<CoureseVO> {@link List<CourseVO>}
     **/
    private List<CourseVO> convertToCoureseVOList(List<AppCourses> appCoureseList) {
        return appCoureseList.stream()
                .map(courses -> new CourseVO()
                        .setId(courses.getId()).setCover(courses.getCover().split(",")[0])
                        .setPriceType(courses.getPriceType())
                        .setCover(courses.getCover().split( ",")[0])
                        .setSellingPrice(courses.getSellingPrice()))
                .collect(Collectors.toList());
    }

    @Override
    public Page<PlaceVO> getPlaceList(GetPlaceListDTO getPlaceListDTO) {
        Page<PlaceVO> page = new Page<>(getPlaceListDTO.getCurrent(), getPlaceListDTO.getSize());
        Page<PlaceVO> placeList = appSiteMapper.getPlaceList(page, getPlaceListDTO.getVenueType());
        List<PlaceVO> records = placeList.getRecords();
        if (ObjectUtil.isNotEmpty(records)) {
            int recordCount = records.size();
            if (recordCount > 0) {
                List<String> placeIds = new ArrayList<>(recordCount);
                for (PlaceVO placeVO : records) {
                    if (placeVO.getId() != null) {
                        placeIds.add(placeVO.getId());
                        if(null != placeVO.getCover()){
                            placeVO.setCover(placeVO.getCover().split(",")[0]);
                        }
                    }
                }
                Map<String, List<AppSitePlace>> sitePlacesMap = Collections.emptyMap();
                Map<String, List<AppSitePriceRules>> priceRulesMap = Collections.emptyMap();
                if (!placeIds.isEmpty()) {
                    List<AppSitePlace> allSitePlaces = appSitePlaceMapper.selectList(
                            Wrappers.<AppSitePlace>lambdaQuery()
                                    .in(AppSitePlace::getSiteId, placeIds)
                                    .eq(AppSitePlace::getDelFlag, 0)
                                    .eq(AppSitePlace::getStatus, 0)
                    );
                    if (!allSitePlaces.isEmpty()) {
                        sitePlacesMap = new HashMap<>(placeIds.size());
                        for (AppSitePlace sitePlace : allSitePlaces) {
                            sitePlacesMap.computeIfAbsent(sitePlace.getSiteId(), k -> new ArrayList<>())
                                    .add(sitePlace);
                        }
                        List<String> sitePlaceIds = new ArrayList<>(allSitePlaces.size());
                        for (AppSitePlace allSitePlace : allSitePlaces) {
                            String id = allSitePlace.getId();
                            if (id != null) {
                                sitePlaceIds.add(id);
                            }
                        }
                        if (!sitePlaceIds.isEmpty()) {
                            List<AppSitePriceRules> allPriceRules = appSitePriceRulesMapper.selectList(
                                    Wrappers.<AppSitePriceRules>lambdaQuery()
                                            .in(AppSitePriceRules::getSitePlaceId, sitePlaceIds)
                                            .eq(AppSitePriceRules::getDelFlag, 0)
                                            .eq(AppSitePriceRules::getStatus, 0)
                            );
                            if (!allPriceRules.isEmpty()) {
                                priceRulesMap = new HashMap<>(sitePlaceIds.size());
                                for (AppSitePriceRules priceRule : allPriceRules) {
                                    priceRulesMap.computeIfAbsent(priceRule.getSitePlaceId(), k -> new ArrayList<>())
                                            .add(priceRule);
                                }
                            }
                        }
                    }
                }
                Map<String, Long> scoreNumMap = new HashMap<>();
                Map<String, Long> scoreSumMap = new HashMap<>();
                if (!placeIds.isEmpty()) {
                    for (String placeId : placeIds) {
                        scoreNumMap.put(placeId, evaluateMapper.findByScoreNum(placeId));
                        scoreSumMap.put(placeId, evaluateMapper.findByAverageScore(placeId));
                    }
                }
                Map<String, String> categoryNameCache = new HashMap<>();
                for (int i = 0; i < recordCount; i++) {
                    PlaceVO placeVO = records.get(i);
                    Long scoreNum = scoreNumMap.get(placeVO.getId());
                    Long scoreSum = scoreSumMap.get(placeVO.getId());
                    if (null == scoreNum) scoreNum = 0L;
                    if (null == scoreSum) scoreSum = 0L;
                    List<String> categoryNames = new ArrayList<>();
                    if (placeVO.getCategoryId() != null) {
                        String[] categoryIds = placeVO.getCategoryId().split(",");
                        for (String categoryId : categoryIds) {
                            String categoryName = categoryNameCache.get(categoryId);
                            if (categoryName == null) {
                                AppCategory category = appCategoryMapper.selectById(categoryId);
                                if (category != null) {
                                    categoryName = category.getName();
                                    categoryNameCache.put(categoryId, categoryName);
                                }
                            }
                            if (categoryName != null) {
                                categoryNames.add(categoryName);
                            }
                        }
                    }

                    processPlaceVO(placeVO, getPlaceListDTO, sitePlacesMap, priceRulesMap, scoreNum, scoreSum, categoryNames);
                }
                sortPlacesIfNecessary(records, getPlaceListDTO.getVenueType());
            }
        }

        return placeList;
    }

    /**
     * 处理单个场地VO数据
     */
    private void processPlaceVO(PlaceVO placeVO, GetPlaceListDTO getPlaceListDTO,
                                Map<String, List<AppSitePlace>> sitePlacesMap,
                                Map<String, List<AppSitePriceRules>> priceRulesMap,
                                Long scoreNum, Long scoreSum, List<String> categoryNames) {
        // 检查是否有票价规则
        boolean ticketWhether = false;
        List<AppSitePlace> sitePlaces = sitePlacesMap.getOrDefault(placeVO.getId(), Collections.emptyList());
        if (!sitePlaces.isEmpty()) {
            for (AppSitePlace sitePlace : sitePlaces) { // 使用增强for循环替代索引循环
                List<AppSitePriceRules> priceRules = priceRulesMap.getOrDefault(
                        sitePlace.getId(), Collections.emptyList());
                if (!priceRules.isEmpty()) {
                    ticketWhether = true;
                    break;
                }
            }
        }
        // 计算距离
        if (placeVO.getLatitude() != null && placeVO.getLongitude() != null) {
            placeVO.setKm(PositionUtil.calculateDistance(
                    getPlaceListDTO.getLatitude(),
                    getPlaceListDTO.getLongitude(),
                    placeVO.getLatitude().doubleValue(),
                    placeVO.getLongitude().doubleValue()));
        } else {
            placeVO.setKm(0.0);
        }
        placeVO.setCategory(categoryNames);
        placeVO.setTicketWhether(ticketWhether);
        placeVO.setGoodRate(calculateAverage(scoreSum, scoreNum));
        placeVO.setComments(scoreNum);
    }

    /**
     * 根据条件排序场地列表
     */
    private void sortPlacesIfNecessary(List<PlaceVO> records, String venueType) {
        if ("0-2".equals(venueType) || "1-1".equals(venueType) || "2-1".equals(venueType)) {
            // 使用数组排序提高性能
            PlaceVO[] placeArray = records.toArray(new PlaceVO[0]);
            Arrays.sort(placeArray, Comparator.comparing(PlaceVO::getKm, Comparator.nullsLast(Double::compareTo)));
            // 复制回原列表
            for (int i = 0; i < placeArray.length; i++) {
                records.set(i, placeArray[i]);
            }
        }
    }

    @Override
    public Object search(SearchDTO searchDTO) {
        switch (searchDTO.getVenueType().charAt(0)) {
            case '0':
                    addAHotWordSearchHistory(searchDTO);
                    return convertSearchPlaceVOPage(searchDTO);
            case '1':
                    addAHotWordSearchHistory(searchDTO);
                    return convertSearchTrainVOPage(searchDTO);
            case '2':
                    addAHotWordSearchHistory(searchDTO);
                    return convertSearchCompetitionVOPage(searchDTO);
            case '3':
                    addAHotWordSearchHistory(searchDTO);
                    return convertSearchInstructorVOPage(searchDTO);
        }

        return new Page<>();
    }

    private void addAHotWordSearchHistory(SearchDTO searchDTO){
        AppSearchHot appSearchHot = appSearchHotMapper.selectOne(Wrappers.<AppSearchHot>lambdaQuery()
                .eq(AppSearchHot::getSearchContent, searchDTO.getKeyword())
                .last("LIMIT 1"));
        if(null == appSearchHot && null != searchDTO.getKeyword() && !searchDTO.getKeyword().isEmpty()){
            LocalDateTime now = LocalDateTime.now();
            Date tenYearsLater = Date.from(now.plusYears(10).atZone(ZoneId.systemDefault()).toInstant());
            appSearchHotMapper.insert(new AppSearchHot()
                    .setSearchContent(searchDTO.getKeyword())
                    .setSearchCount(1)
                    .setIsActive(1)
                    .setVenueType(searchDTO.getVenueType())
                    .setIsRecommend(0)
                    .setStartTime(new Date()).setEndTime(tenYearsLater));
        }else {
            assert appSearchHot != null;
            appSearchHotMapper.updateById(appSearchHot.setSearchCount(appSearchHot.getSearchCount() + 1));
        }
    }

    @Override
    public List<AppSearchHot> getHotSearch() {
        return appSearchHotMapper.selectList(Wrappers.<AppSearchHot>lambdaQuery()
                // 新增条件：当前时间在 startTime 和 endTime 之间
                .le(AppSearchHot::getStartTime, new Date())  // 开始时间 <= 当前时间
                .ge(AppSearchHot::getEndTime, new Date())
                .eq(AppSearchHot::getIsActive,1)  // 结束时间 >= 当前时间
                .last("LIMIT 10")
                .orderByDesc(AppSearchHot::getSearchCount));
    }

    /**
     * @Author SheepHy
     * @Description 全局搜索场地分页查询
     * @Date 11:05 2025/7/7
     * @Param searchDTO {@link SearchDTO}
     * @return Page<SearchVO.SearchPlaceVO>
     **/
    private Page<SearchVO.SearchPlaceVO> convertSearchPlaceVOPage(SearchDTO searchDTO) {
        Page<SearchVO.SearchPlaceVO> page = new Page<>(searchDTO.getCurrent(), searchDTO.getSize());
        Page<SearchVO.SearchPlaceVO> searchPlaceVOPage = appSiteMapper.convertSearchPlaceVOPage(page, searchDTO);
        searchPlaceVOPage.getRecords().forEach(placeVO -> {
            AppSite appSite = appSiteMapper.selectById(placeVO.getId());
            placeVO.setKm(PositionUtil.calculateDistance(searchDTO.getLatitude(), searchDTO.getLongitude(), appSite.getLatitude().doubleValue(), appSite.getLongitude().doubleValue()))
                    .setCategory(getCategoryName(placeVO.getCategoryId())).setCover(placeVO.getCover().split(",")[0]);

        });
        if(searchDTO.getVenueType().equals("0-2")
                || searchDTO.getVenueType().equals("1-1")
                || searchDTO.getVenueType().equals("2-1")){
            // 按 km 升序排序（searchDTO）
            searchPlaceVOPage.getRecords().sort((p1, p2) -> {
                Double km1 = p1.getKm();
                Double km2 = p2.getKm();
                return km1.compareTo(km2);
            });
        }
        return searchPlaceVOPage;
    }

    /**
     * @Author SheepHy
     * @Description 根据类目ID获取完整的类目名称
     * @Date 13:31 2025/7/7
     * @Param categoryId 类目ID
     * @return List<String>
     **/
    private List<String> getCategoryName(String categoryId) {
        List<String> list = new ArrayList<>();
        if(null != categoryId){
            String[] split = categoryId.split(",");
            Arrays.stream(split).forEach(id -> {
                list.add(appCategoryMapper.selectById(id).getName());
            });
        }
        return list;
    }

    /**
     * @Author SheepHy
     * @Description 培训课程分页查询
     * @Date 13:37 2025/7/7
     * @Param searchDTO {@link SearchDTO}
     * @return Page<SearchVO.SearchTrainVO>
     **/
    private Page<SearchVO.SearchTrainVO> convertSearchTrainVOPage(SearchDTO searchDTO) {
        Page<SearchVO.SearchTrainVO> page = new Page<>(searchDTO.getCurrent(), searchDTO.getSize());
        Page<SearchVO.SearchTrainVO> searchTrainVOPage = appCoursesMapper.convertSearchTrainVOPage(page, searchDTO);
        searchTrainVOPage.getRecords().forEach(trainVO -> {
            AppSite appSite = appSiteMapper.selectById(trainVO.getSiteId());
            trainVO.setKm(PositionUtil.calculateDistance(searchDTO.getLatitude(), searchDTO.getLongitude(), appSite.getLatitude().doubleValue(), appSite.getLongitude().doubleValue()));
        });
        return searchTrainVOPage;
    }

    /**
     * @Author SheepHy
     * @Description 赛事分页查询
     * @Date 14:04 2025/7/7
     * @Param searchDTO {@link SearchDTO}
     * @return Page<SearchVO.SearchRaceVO>
     **/
    private Page<SearchVO.SearchRaceVO> convertSearchCompetitionVOPage(SearchDTO searchDTO) {
        Page<SearchVO.SearchRaceVO> page = new Page<>(searchDTO.getCurrent(), searchDTO.getSize());
        Page<SearchVO.SearchRaceVO> searchCompetitionVOPage = appGameMapper.convertSearchCompetitionVOPage(page, searchDTO);
        searchCompetitionVOPage.getRecords().forEach(competitionVO -> {
            AppSite appSite = appSiteMapper.selectOne(
                    Wrappers.<AppSite>lambdaQuery().eq(AppSite::getId, competitionVO.getSiteId()));
            if(null != appSite){
                competitionVO.setKm(PositionUtil.calculateDistance(
                        searchDTO.getLatitude(), searchDTO.getLongitude(),
                        appSite.getLatitude().doubleValue(), appSite.getLongitude().doubleValue()));
                if(competitionVO.getSiteType() == 1){
                    competitionVO.setKm(PositionUtil.calculateDistance(
                            searchDTO.getLatitude(), searchDTO.getLongitude(),
                            competitionVO.getLatitude().doubleValue(), competitionVO.getLongitude().doubleValue()));
                }
            }
            // 获取价格规则并判断 type
            List<AppGamePriceRules> appGamePriceRules = appGamePriceRulesMapper.selectList(
                    Wrappers.<AppGamePriceRules>lambdaQuery()
                            .eq(AppGamePriceRules::getGameId, competitionVO.getId()));
            int targetType = -1; // 默认无效状态
            if (appGamePriceRules != null && !appGamePriceRules.isEmpty()) {
                boolean hasType0 = appGamePriceRules.stream()
                        .anyMatch(rule -> rule.getType() == 0);
                boolean hasType1 = appGamePriceRules.stream()
                        .anyMatch(rule -> rule.getType() == 1);
                if (hasType0 && hasType1) {
                    targetType = 2;
                } else if (hasType0) {
                    targetType = 0;
                } else if (hasType1) {
                    targetType = 1;
                }
            }
            competitionVO.setType(targetType);
            competitionVO.setKm(PositionUtil.calculateDistance(searchDTO.getLatitude(), searchDTO.getLongitude(), appSite.getLatitude().doubleValue(), appSite.getLongitude().doubleValue()));
            competitionVO.setCategory(getCategoryName(appSite.getCategoryId()));
        });
        return page;
    }

    public static BigDecimal calculateAverage(Long scoreSum, Long scoreNum) {
        if (scoreNum == 0L) {
            return  BigDecimal.valueOf(0).setScale(1 , RoundingMode.DOWN);
        }

        // 将分子和分母都转换为BigDecimal
        BigDecimal sum = new BigDecimal(scoreSum);
        BigDecimal num = new BigDecimal(scoreNum);

        // 计算平均数，保留1位小数并四舍五入
        return sum.divide(num, 1, RoundingMode.HALF_UP);
    }

    /** 
     * @Author SheepHy
     * @Description
     * @Date 14:43 2025/7/7
     * @Param searchDTO {@link SearchDTO}
     * @return Page<SearchVO.SearchInstructorVO>
     **/
    private Page<SearchVO.SearchInstructorVO> convertSearchInstructorVOPage(SearchDTO searchDTO) {
        Page<SearchVO.SearchInstructorVO> page = new Page<>(searchDTO.getCurrent(), searchDTO.getSize());
        Page<SearchVO.SearchInstructorVO> searchInstructorVOPage = appInstructorMapper.convertSearchInstructorVOPage(page, searchDTO);
        searchInstructorVOPage.getRecords().forEach(instructorVO -> {
            List<String> list = new ArrayList<>();
            List.of(instructorVO.getTrainingPrograms().split(",")).forEach(item -> {
                String str = appCategoryMapper.selectById(item).getName();
                list.add(str);
            });
            instructorVO.setList( list);
            // 获取该教练的课程（最多取2个）
            List<AppCourses> courses = appCoursesMapper.selectList(
                    Wrappers.<AppCourses>lambdaQuery().eq(AppCourses::getUserId, instructorVO.getUserId()).last("LIMIT 2"));
            List<SearchVO.SearchCoursesVO> courseInfoVOS = courses.stream()
                    .map(course -> {
                        SearchVO.SearchCoursesVO vo = new SearchVO.SearchCoursesVO();
                        BeanUtils.copyProperties(course, vo);
                        vo.setSales(getCourseSalesCount(course.getId()));
                        return vo;
                    })
                    .collect(Collectors.toList());
            AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getOrgCode, instructorVO.getOrgCode()));
            if (appSite!=null&& ObjectUtils.isNotEmpty(appSite.getLatitude())&&ObjectUtils.isNotEmpty(appSite.getLongitude())){
                instructorVO.setKm(PositionUtil.calculateDistance(searchDTO.getLatitude(), searchDTO.getLongitude(), appSite.getLatitude().doubleValue(), appSite.getLongitude().doubleValue()))
                        .setCourseList(courseInfoVOS);
            }
        });
        return searchInstructorVOPage;
    }

    /**
     * @Author SheepHy
     * @Description 计算当前课程销售数
     * @Date 15:47 2025/7/8
     * @Param id 课程id
     * @return int 课程年销售数
     **/
    private int getCourseSalesCount(String id) {
        return Math.toIntExact(appOrderProInfoMapper.selectCount(
                Wrappers.<AppOrderProInfo>lambdaQuery()
                        .eq(AppOrderProInfo::getProductId, id)
                        .ne(AppOrderProInfo::getType,6)
                        .ne(AppOrderProInfo::getOrderStatus,0)
                        .ne(AppOrderProInfo::getOrderStatus,4)
                        .ne(AppOrderProInfo::getOrderStatus,5)
                        .ne(AppOrderProInfo::getOrderStatus,6)
        ));
    }

    /**
     * @description 根据教练ID获取教练订单数
     * params
     * @author SheepHy
     * @date 2025/9/10
     * return   {@link }
     **/
    private int getInstructorOrderNum(String id) {
        List<String> courseIds = appCoursesMapper.selectList(
                        Wrappers.<AppCourses>lambdaQuery()
                                .select(AppCourses::getId)
                                .eq(AppCourses::getUserId, id)
                ).stream()
                .map(AppCourses::getId)
                .collect(Collectors.toList());
        if(courseIds.isEmpty()) return 0;
        return Math.toIntExact(appOrderProInfoMapper.selectCount(
                Wrappers.<AppOrderProInfo>lambdaQuery()
                        .eq(AppOrderProInfo::getStatus,0)
                        .ne(AppOrderProInfo::getType,6)
                        .ne(AppOrderProInfo::getOrderStatus,0)
                        .ne(AppOrderProInfo::getOrderStatus,4)
                        .ne(AppOrderProInfo::getOrderStatus,5)
                        .ne(AppOrderProInfo::getOrderStatus,6)
                        .eq(AppOrderProInfo::getDelFlag,0)
                        .in(AppOrderProInfo::getProductId, courseIds)
        ));
    }

    /**
     * @description 根据教练ID获取授课人数(基于familyUserId去重统计)
     * @param id 教练ID
     * @author SheepHy
     * @date 2025/9/10
     * @return 去重后的授课人数
     **/
    private int getInstructorTeachingNum(String id) {
        List<String> courseIds = appCoursesMapper.selectList(
                        Wrappers.<AppCourses>lambdaQuery()
                                .select(AppCourses::getId)
                                .eq(AppCourses::getUserId, id)
                ).stream()
                .map(AppCourses::getId)
                .collect(Collectors.toList());
        if (courseIds.isEmpty()) return 0;
        // 查询不重复的familyUserId数量
        List<String> distinctFamilyUserIds = appOrderProInfoMapper.selectList(
                        Wrappers.<AppOrderProInfo>lambdaQuery()
                                .select(AppOrderProInfo::getFamilyUserId)
                                .in(AppOrderProInfo::getProductId, courseIds)
                                .ne(AppOrderProInfo::getType,6)
                                .ne(AppOrderProInfo::getOrderStatus,0)
                                .ne(AppOrderProInfo::getOrderStatus,4)
                                .ne(AppOrderProInfo::getOrderStatus,5)
                                .ne(AppOrderProInfo::getOrderStatus,6)
                                .eq(AppOrderProInfo::getStatus, 0)
                                .eq(AppOrderProInfo::getDelFlag, 0)
                                .isNotNull(AppOrderProInfo::getFamilyUserId)
                ).stream()
                .map(AppOrderProInfo::getFamilyUserId)
                .distinct()
                .collect(Collectors.toList());

        return distinctFamilyUserIds.size();
    }

}
