package com.pig4cloud.pig.statistics.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pig.statistics.Util.ConfigUtils;
import com.pig4cloud.pig.statistics.Util.PageUtils;
import com.pig4cloud.pig.statistics.api.dto.uninstall.*;
import com.pig4cloud.pig.statistics.api.entity.ConfigItem;
import com.pig4cloud.pig.statistics.api.entity.uninstall.*;
import com.pig4cloud.pig.statistics.api.vo.uninstall.*;
import com.pig4cloud.pig.statistics.mapper.StatTrendSummaryMapper;
import com.pig4cloud.pig.statistics.mapper.StatDeviceTimeMapper;
import com.pig4cloud.pig.statistics.mapper.StatDeviceCountMapper;
import com.pig4cloud.pig.statistics.mapper.StatDeviceInterfereMapper;
import com.pig4cloud.pig.statistics.mapper.StatDeviceActionMapper;
import com.pig4cloud.pig.statistics.mapper.StatPortraitMapper;
import com.pig4cloud.pig.statistics.mapper.StatPredictMapper;
import com.pig4cloud.pig.statistics.mapper.StatInstallRatioMapper;
import com.pig4cloud.pig.statistics.service.UninstallAnalyseService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: wcl
 * @date: 2025-08-13
 * @description: 流失卸载分析服务实现
 */
@Slf4j
@Service
public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {

	private static final Random random = new Random();

	@Autowired
	private StatTrendSummaryMapper statTrendSummaryMapper;
	@Autowired
	private StatDeviceTimeMapper statDeviceTimeMapper;
	@Autowired
	private StatDeviceCountMapper statDeviceCountMapper;
	@Autowired
	private StatDeviceInterfereMapper statDeviceInterfereMapper;
	@Autowired
	private StatDeviceActionMapper statDeviceActionMapper;
	@Autowired
	private StatPortraitMapper statPortraitMapper;
	@Autowired
	private StatInstallRatioMapper statInstallRatioMapper;
	@Autowired
	private StatPredictMapper statPredictMapper;

	@Override
	public UninstallTrendVO getUninstallTrend(GetUninstallTrendDTO dto) {
		LocalDate startDate, endDate;
		String timeUnit = dto.getTimeUnit() == null ? "week" : dto.getTimeUnit();
		LocalDate now = LocalDate.now();
		if ("week".equalsIgnoreCase(timeUnit)) {
			if (now.getDayOfWeek().getValue() < DayOfWeek.THURSDAY.getValue()) {
				startDate = now.minusWeeks(2).with(DayOfWeek.MONDAY);
				endDate = now.minusWeeks(2).with(DayOfWeek.SUNDAY);
			} else {
				startDate = now.minusWeeks(1).with(DayOfWeek.MONDAY);
				endDate = now.minusWeeks(1).with(DayOfWeek.SUNDAY);
			}
		} else if ("month".equalsIgnoreCase(timeUnit)) {
			if (now.getDayOfMonth() < 4) {
				LocalDate lastMonth = now.minusMonths(2);
				startDate = lastMonth.withDayOfMonth(1);
				endDate = lastMonth.with(TemporalAdjusters.lastDayOfMonth());
			} else {
				LocalDate lastMonth = now.minusMonths(1);
				startDate = lastMonth.withDayOfMonth(1);
				endDate = lastMonth.with(TemporalAdjusters.lastDayOfMonth());
			}
		} else {
			startDate = now;
			endDate = now;
		}
		// 支持前端传参覆盖
		if (!StringUtils.isEmpty(dto.getStartDate())) {
			startDate = LocalDate.parse(dto.getStartDate());
		}
		if (!StringUtils.isEmpty(dto.getEndDate())) {
			endDate = LocalDate.parse(dto.getEndDate());
		}
		QueryWrapper<MktTrendSummary> wrapper = new QueryWrapper<>();
		wrapper.between("stat_date", startDate, endDate);
		if (!StringUtils.isEmpty(dto.getAppId())) {
			wrapper.eq("app_id", dto.getAppId());
		}
		if (!StringUtils.isEmpty(dto.getChannel())) {
			wrapper.eq("channel", dto.getChannel());
		}
		if (!StringUtils.isEmpty(dto.getVersion())) {
			wrapper.eq("app_version", dto.getVersion());
		}
		wrapper.eq("stat_cycle", timeUnit);
		List<MktTrendSummary> list = statTrendSummaryMapper.selectList(wrapper);

		UninstallTrendVO vo = new UninstallTrendVO();

		int uninstallCount = 0, recallCount = 0;
		Double uninstallRate = 0.0, recallRate = 0.0;
		if (list != null && !list.isEmpty()) {
			for (MktTrendSummary summary : list) {
				if (summary.getTrendType() != null) {
					// 卸载
					if (summary.getTrendType() == 0) {
						uninstallCount += summary.getCount();
						uninstallRate += summary.getRate();
					}
					// 召回
					else if (summary.getTrendType() == 1) {
						recallCount += summary.getCount();
						recallRate += summary.getRate();
					}
				}
			}
		}
		vo.setStartDate(String.valueOf(startDate));
		vo.setEndDate(String.valueOf(endDate));
		vo.setUninstallCounts(uninstallCount);
		vo.setRecallCounts(recallCount);
		vo.setUninstallRates(uninstallRate);
		vo.setRecallRates(recallRate);

		return vo;
	}

	@Override
	public Page<UninstallTrendDtlVO> getUninstallTrendDetail(GetUninstallTrendDetailDTO dto) {
		// 分页参数
		int pageNum = dto.getPageNum() == null ? 1 : dto.getPageNum();
		int pageSize = dto.getPageSize() == null ? 10 : dto.getPageSize();

		String timeUnit = StringUtils.isEmpty(dto.getTimeUnit()) ? "week" : dto.getTimeUnit();
		QueryWrapper<MktTrendSummary> wrapper = new QueryWrapper<>();

		if (!StringUtils.isEmpty(dto.getAppId())) {
			wrapper.eq("app_id", dto.getAppId());
		}
		if (!StringUtils.isEmpty(dto.getChannel())) {
			wrapper.eq("channel", dto.getChannel());
		}
		if (!StringUtils.isEmpty(dto.getVersion())) {
			wrapper.eq("app_version", dto.getVersion());
		}
		wrapper.eq("stat_cycle", timeUnit);

		if (!StringUtils.isEmpty(dto.getStartDate()) && !StringUtils.isEmpty(dto.getEndDate())) {
			wrapper.between("stat_date", dto.getStartDate(), dto.getEndDate());
		}

		List<MktTrendSummary> list = statTrendSummaryMapper.selectList(wrapper);
		log.info("查询结果数量: {}", list.size());

		// 使用Stream API优化分组和统计逻辑
		List<UninstallTrendDtlVO> voList = new ArrayList<>(list.stream()
				.collect(Collectors.groupingBy(
						summary -> getCycleKey(summary.getStatDate(), timeUnit),
						TreeMap::new,
						Collectors.collectingAndThen(
								Collectors.toList(),
								summaries -> buildUninstallTrendDtlVO(summaries, timeUnit)
						)
				))
				.values());

		log.info("分页参数: pageNum={}, pageSize={}, voList.size={}", pageNum, pageSize, voList.size());

		// 使用PageUtils工具类处理分页
		return PageUtils.buildPage(voList, pageNum, pageSize);
	}

	/**
	 * 获取周期分组key
	 */
	private String getCycleKey(java.util.Date statDate, String timeUnit) {
		LocalDate date = statDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
		if ("week".equalsIgnoreCase(timeUnit)) {
			return date.with(DayOfWeek.MONDAY).toString();
		} else if ("month".equalsIgnoreCase(timeUnit)) {
			return date.withDayOfMonth(1).toString();
		} else {
			return date.toString();
		}
	}

	/**
	 * 构建卸载趋势明细VO
	 */
	private UninstallTrendDtlVO buildUninstallTrendDtlVO(List<MktTrendSummary> summaries, String timeUnit) {
		LocalDate start = LocalDate.parse(getCycleKey(summaries.get(0).getStatDate(), timeUnit));
		LocalDate end;

		if ("week".equalsIgnoreCase(timeUnit)) {
			end = start.with(DayOfWeek.SUNDAY);
		} else if ("month".equalsIgnoreCase(timeUnit)) {
			end = start.with(TemporalAdjusters.lastDayOfMonth());
		} else {
			end = start;
		}

		// 使用Stream API统计数据
		int uninstallCount = summaries.stream()
				.filter(summary -> summary.getTrendType() != null && summary.getTrendType() == 0)
				.mapToInt(MktTrendSummary::getCount)
				.sum();

		int recallCount = summaries.stream()
				.filter(summary -> summary.getTrendType() != null && summary.getTrendType() == 1)
				.mapToInt(MktTrendSummary::getCount)
				.sum();

		UninstallTrendDtlVO vo = new UninstallTrendDtlVO();
		vo.setStartDate(start.toString());
		vo.setEndDate(end.toString());
		vo.setUninstallCounts(uninstallCount);
		vo.setRecallCounts(recallCount);

		return vo;
	}

	@Override
	public UninstallInsightVO getUninstallDeviceActive(GetUninstallInsightDTO dto) {
		return getUninstallDeviceActiveVO(dto);
	}

	public UninstallInsightVO getUninstallDeviceActiveVO(GetUninstallInsightDTO dto) {

		Map<String, LocalDate> timeRangeMap = getTimeRangeMap(StringUtils.isEmpty(dto.getType()) ? "week" : dto.getType());
		QueryWrapper<MktDeviceTime> wrapper = new QueryWrapper<>();
		if (!StringUtils.isEmpty(dto.getType())) {
			wrapper.eq("type", dto.getType());
		}

		// 添加时间范围查询
		wrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
		// 动态添加其他查询条件
		if (!StringUtils.isEmpty(dto.getAppId())) wrapper.eq("app_id", dto.getAppId());
		if (!StringUtils.isEmpty(dto.getChannel())) wrapper.eq("channel", dto.getChannel());
		if (!StringUtils.isEmpty(dto.getVersion())) wrapper.eq("app_version", dto.getVersion());

		List<MktDeviceTime> list = statDeviceTimeMapper.selectList(wrapper);
		List<InstallStockVO> voList = new ArrayList<>();
		for (MktDeviceTime entity : list) {
			InstallStockVO vo = new InstallStockVO();
			ConfigItem configValue = ConfigUtils.getConfigValue("Time-range", entity.getTimeRange());
			vo.setTime(configValue.getLabel());
			vo.setUninstallCount(entity.getDeviceCount());
			vo.setUninstallRate(entity.getRate());
			voList.add(vo);
		}
		UninstallInsightVO result = new UninstallInsightVO();
		result.setLifecycleDistribution(voList);
		return result;
	}

	private Map<String, LocalDate> getTimeRangeMap(String timeUnit) {

		Map<String, LocalDate> timeRangeMap = new HashMap<>();
		// 根据当前日期计算查询时间范围
		LocalDate now = LocalDate.now();
		LocalDate startDate, endDate;
		if (StringUtils.isEmpty(timeUnit)) timeUnit = "week";

		if ("week".equalsIgnoreCase(timeUnit)) {
			// 默认查上周：本周一~三查上上周，本周四~日查上周
			if (now.getDayOfWeek().getValue() < DayOfWeek.THURSDAY.getValue()) {
				startDate = now.minusWeeks(2).with(DayOfWeek.MONDAY);
				endDate = now.minusWeeks(2).with(DayOfWeek.SUNDAY);
			} else {
				startDate = now.minusWeeks(1).with(DayOfWeek.MONDAY);
				endDate = now.minusWeeks(1).with(DayOfWeek.SUNDAY);
			}
		} else if ("month".equalsIgnoreCase(timeUnit)) {
			// 查上月：本月1-3号查上上月，本月4号及以后查上月
			if (now.getDayOfMonth() < 4) {
				LocalDate lastMonth = now.minusMonths(2);
				startDate = lastMonth.withDayOfMonth(1);
				endDate = lastMonth.with(TemporalAdjusters.lastDayOfMonth());
			} else {
				LocalDate lastMonth = now.minusMonths(1);
				startDate = lastMonth.withDayOfMonth(1);
				endDate = lastMonth.with(TemporalAdjusters.lastDayOfMonth());
			}
		} else {
			// 默认查上周
			if (now.getDayOfWeek().getValue() < DayOfWeek.THURSDAY.getValue()) {
				startDate = now.minusWeeks(2).with(DayOfWeek.MONDAY);
				endDate = now.minusWeeks(2).with(DayOfWeek.SUNDAY);
			} else {
				startDate = now.minusWeeks(1).with(DayOfWeek.MONDAY);
				endDate = now.minusWeeks(1).with(DayOfWeek.SUNDAY);
			}
		}
		timeRangeMap.put("startDate", startDate);
		timeRangeMap.put("endDate", endDate);
		return timeRangeMap;
	}

	@Override
	public UninstallBeforeVO uninstallBefore(GetUninstallInsightDTO dto) {

		Map<String, LocalDate> timeRangeMap = new HashMap<>();
		if (!StringUtils.isEmpty(dto.getCycle())) {
			timeRangeMap = getTimeRangeMap(dto.getCycle());
		}
		// 1. 卸载时间差分布
		QueryWrapper<MktDeviceTime> timeWrapper = new QueryWrapper<>();
		if (timeRangeMap.get("startDate") != null && timeRangeMap.get("endDate") != null) {
			timeWrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
		}
		timeWrapper.eq("type", dto.getType());
		if (!StringUtils.isEmpty(dto.getAppId())) timeWrapper.eq("app_id", dto.getAppId());
		if (!StringUtils.isEmpty(dto.getChannel())) timeWrapper.eq("channel", dto.getChannel());
		if (!StringUtils.isEmpty(dto.getVersion())) timeWrapper.eq("app_version", dto.getVersion());
		List<MktDeviceTime> timeList = statDeviceTimeMapper.selectList(timeWrapper);
		List<UninstallTimeDiffVO> timeDiffs = new ArrayList<>();
		for (MktDeviceTime entity : timeList) {
			UninstallTimeDiffVO vo = new UninstallTimeDiffVO();
			ConfigItem configValue = ConfigUtils.getConfigValue("Time-range", entity.getTimeRange());
			vo.setTime(configValue.getLabel());
			vo.setCount(entity.getDeviceCount());
			vo.setRate(entity.getRate());
			timeDiffs.add(vo);
		}
		// 2. 卸载前7天使用次数分布
		QueryWrapper<MktDeviceCount> countWrapper = new QueryWrapper<>();
		countWrapper.eq("type", dto.getType());
		countWrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
		if (!StringUtils.isEmpty(dto.getAppId())) countWrapper.eq("app_id", dto.getAppId());
		if (!StringUtils.isEmpty(dto.getChannel())) countWrapper.eq("channel", dto.getChannel());
		if (!StringUtils.isEmpty(dto.getVersion())) countWrapper.eq("app_version", dto.getVersion());
		List<MktDeviceCount> countList = statDeviceCountMapper.selectList(countWrapper);
		List<UninstallBeforeSevenVO> beforeSevens = new ArrayList<>();
		for (MktDeviceCount entity : countList) {
			UninstallBeforeSevenVO vo = new UninstallBeforeSevenVO();
			ConfigItem configValue = ConfigUtils.getConfigValue("Count_range", String.valueOf(entity.getCountRange()));

			vo.setTime(configValue.getLabel());
			vo.setCount(entity.getNum());
			vo.setRate(entity.getRate());
			beforeSevens.add(vo);
		}


		UninstallBeforeVO result = new UninstallBeforeVO();
		result.setUninstallTimeDiffs(timeDiffs);
		result.setUninstallBeforeSevens(beforeSevens);
		return result;
	}

	/**
	 * 体验干扰
	 *
	 * @param dto
	 */
	@Override
	public UninstallBeforeInterfereVO uninstallInterfere(GetUninstallInsightDTO dto) {

		UninstallBeforeInterfereVO result = new UninstallBeforeInterfereVO();

		Map<String, LocalDate> timeRangeMap = new HashMap<>();
		if (!StringUtils.isEmpty(dto.getCycle())) {
			timeRangeMap = getTimeRangeMap(dto.getCycle());
		}
		ConfigItem configValue = null;
		if (!StringUtils.isEmpty(dto.getType())) {
			configValue = ConfigUtils.getConfigValue("Interfere_type", dto.getType());
		}
		List<Map<String, Integer>> value = new ArrayList<>();
		// 3. 卸载前干扰指标
		QueryWrapper<MktDeviceInterfere> interfereWrapper = new QueryWrapper<>();
		interfereWrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
		interfereWrapper.eq("interfere_type", dto.getType());
		if (!StringUtils.isEmpty(dto.getAppId())) interfereWrapper.eq("app_id", dto.getAppId());
		if (!StringUtils.isEmpty(dto.getChannel())) interfereWrapper.eq("channel", dto.getChannel());
		if (!StringUtils.isEmpty(dto.getVersion())) interfereWrapper.eq("app_version", dto.getVersion());
		List<MktDeviceInterfere> interfereList = statDeviceInterfereMapper.selectList(interfereWrapper);
		Map<String, Map<String, Integer>> interfereMap = new LinkedHashMap<>();
		for (MktDeviceInterfere entity : interfereList) {
			Map<String, Integer> map = new HashMap<>();
			ConfigItem countValue = ConfigUtils.getConfigValue("Count_range", String.valueOf(entity.getCountRange()));
			map.put(countValue.getLabel(), entity.getNum());
			value.add(map);
		}
		if (configValue != null) {
			result.setType(configValue.getLabel());
		} else {
			result.setType("");
		}
		result.setValue(value);
		return result;
	}

	/**
	 * 行为还原
	 *
	 * @param dto
	 */
	@Override
	public UninstallBeforeActionVO uninstallAction(GetUninstallInsightDTO dto) {

		UninstallBeforeActionVO result = new UninstallBeforeActionVO();

		Map<String, LocalDate> timeRangeMap = new HashMap<>();
		if (!StringUtils.isEmpty(dto.getCycle())) {
			timeRangeMap = getTimeRangeMap(dto.getCycle());
		}

		ConfigItem configValue = null;
		if (!StringUtils.isEmpty(dto.getType())) {
			configValue = ConfigUtils.getConfigValue("Action_type", dto.getType());
		}
		// 4. 卸载前行为还原
		QueryWrapper<MktDeviceAction> actionWrapper = new QueryWrapper<>();
		actionWrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
		actionWrapper.eq("action_type", dto.getType());
		if (!StringUtils.isEmpty(dto.getAppId())) actionWrapper.eq("app_id", dto.getAppId());
		if (!StringUtils.isEmpty(dto.getChannel())) actionWrapper.eq("channel", dto.getChannel());
		if (!StringUtils.isEmpty(dto.getVersion())) actionWrapper.eq("app_version", dto.getVersion());
		List<MktDeviceAction> actionList = statDeviceActionMapper.selectList(actionWrapper);
		List<Map<String, Integer>> list = new ArrayList<>();
		for (MktDeviceAction entity : actionList) {
			Map<String, Integer> map = new HashMap<>();
			ConfigItem actionType = ConfigUtils.getConfigValue("Action_type", String.valueOf(entity.getActionType()));
			map.put(actionType.getLabel(), entity.getTriggerCount());

			list.add(map);
		}
		result.setValue(list);

		if (configValue != null) {
			result.setActionType(configValue.getLabel());
		} else {
			result.setActionType("");
		}

		return result;
	}

	@Override
	public List<UninstallOfterAPPOV> uninstallAfter(GetUninstallInsightDTO dto) {

		Map<String, LocalDate> timeRangeMap = new HashMap<>();

		if (!StringUtils.isEmpty(dto.getCycle())) {
			timeRangeMap = getTimeRangeMap(dto.getCycle());
		}

		QueryWrapper<MktDeviceTime> wrapper = new QueryWrapper<>();
		if (!StringUtils.isEmpty(dto.getType())){
			wrapper.eq("type", dto.getType());
		}
		if (!timeRangeMap.isEmpty()){
			wrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
		}
		if (!StringUtils.isEmpty(dto.getAppId())) wrapper.eq("app_id", dto.getAppId());
		if (!StringUtils.isEmpty(dto.getChannel())) wrapper.eq("channel", dto.getChannel());
		if (!StringUtils.isEmpty(dto.getVersion())) wrapper.eq("app_version", dto.getVersion());
		List<MktDeviceTime> list = statDeviceTimeMapper.selectList(wrapper);
		List<UninstallOfterAPPOV> result = new ArrayList<>();
		for (MktDeviceTime entity : list) {
			UninstallOfterAPPOV vo = new UninstallOfterAPPOV();
			ConfigItem actionType = ConfigUtils.getConfigValue("app_type", entity.getType());
			vo.setAppName(!StringUtils.isEmpty(actionType.getLabel()) ? actionType.getLabel() : ""); //
			vo.setCount(entity.getDeviceCount());
			vo.setProportion(entity.getRate() != null ? entity.getRate().toString() : null);
			result.add(vo);
		}
		return result;
	}

	@Override
	public List<UninstallSYSOV> uninstallSys(GetUninstallInsightDTO dto) {

		Map<String, LocalDate> timeRangeMap = new HashMap<>();

		if (!StringUtils.isEmpty(dto.getCycle())) {
			timeRangeMap = getTimeRangeMap(dto.getCycle());
		}

		QueryWrapper<MktDeviceTime> wrapper = new QueryWrapper<>();
		if (!StringUtils.isEmpty(dto.getType())){
			wrapper.eq("type", dto.getType());
		}
		if (!timeRangeMap.isEmpty()){
			wrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
		}
		if (!StringUtils.isEmpty(dto.getAppId())) wrapper.eq("app_id", dto.getAppId());
		if (!StringUtils.isEmpty(dto.getChannel())) wrapper.eq("channel", dto.getChannel());
		if (!StringUtils.isEmpty(dto.getVersion())) wrapper.eq("app_version", dto.getVersion());
		List<MktDeviceTime> list = statDeviceTimeMapper.selectList(wrapper);
		Map<String, List<Map<String, Integer>>> sysMap = new LinkedHashMap<>();
		for (MktDeviceTime entity : list) {
			sysMap.computeIfAbsent(entity.getTimeRange(), k -> new ArrayList<>())
					.add(Collections.singletonMap(entity.getAppVersion(), entity.getDeviceCount()));
		}
		List<UninstallSYSOV> result = new ArrayList<>();
		for (Map.Entry<String, List<Map<String, Integer>>> entry : sysMap.entrySet()) {
			UninstallSYSOV vo = new UninstallSYSOV();
			vo.setDimensionName(entry.getKey());
			vo.setDistribution(entry.getValue());
			result.add(vo);
		}
		return result;
	}

	@Override
	public UninstallPortraitOV getUninstallPortrait(UninstallPortraitDTO dto) {
		UninstallPortraitOV vo = new UninstallPortraitOV();
		
		QueryWrapper<MktPortrait> wrapper = new QueryWrapper<>();
		
		if (!StringUtils.isEmpty(dto.getTimeUnit())) {
			wrapper.eq("stat_cycle", dto.getTimeUnit());
		}
		
		if (!StringUtils.isEmpty(dto.getAppId())) {
			wrapper.eq("app_id", dto.getAppId());
		}
		if (!StringUtils.isEmpty(dto.getChannel())) {
			wrapper.eq("channel", dto.getChannel());
		}
		if (!StringUtils.isEmpty(dto.getVersion())) {
			wrapper.eq("app_version", dto.getVersion());
		}
		
		LocalDate startDate, endDate;
		if (!StringUtils.isEmpty(dto.getStartDate())) {
			startDate = LocalDate.parse(dto.getStartDate());
		} else {
			// 默认当周第一天
			LocalDate now = LocalDate.now();
			startDate = now.with(DayOfWeek.MONDAY);
		}
		
		if ("week".equalsIgnoreCase(dto.getTimeUnit())) {
			endDate = startDate.with(DayOfWeek.SUNDAY);
		} else if ("month".equalsIgnoreCase(dto.getTimeUnit())) {
			endDate = startDate.with(TemporalAdjusters.lastDayOfMonth());
		} else {
			endDate = startDate.with(DayOfWeek.SUNDAY);
		}
		
		wrapper.between("stat_date", startDate, endDate);
		
		List<MktPortrait> portraitList = statPortraitMapper.selectList(wrapper);
		
		// 1. 卸载数量统计
		UninstallPortraitSumOV sum = new UninstallPortraitSumOV();
		sum.setTimeUnit(dto.getTimeUnit() == null ? "week" : dto.getTimeUnit());
		
		int totalCount = portraitList.stream()
			.filter(p -> p.getStatus() != null)
			.mapToInt(p -> p.getPhaseCount() != null ? p.getPhaseCount() : 0)
			.sum();
		sum.setCount(totalCount);
		vo.setUninstallCount(sum);
		
		// 2. 用户特征情况（易卸载和不易卸载特征）
		List<UninstallPortraitCharacterVO> charList = new ArrayList<>();
		
		List<MktPortrait> easyFeatures = portraitList.stream()
			.filter(p -> p.getStatus() != null && p.getStatus() == 0)
			.toList();
		
		for (MktPortrait feature : easyFeatures) {
			UninstallPortraitCharacterVO c = new UninstallPortraitCharacterVO();
			c.setName(feature.getFeatureName());
			c.setTgi(feature.getTgi());
			c.setPercent(feature.getPercent());
			c.setStatus(0);
			charList.add(c);
		}
		
		List<MktPortrait> hardFeatures = portraitList.stream()
			.filter(p -> p.getStatus() != null && p.getStatus() == 1)
			.toList();
		
		for (MktPortrait feature : hardFeatures) {
			UninstallPortraitCharacterVO c = new UninstallPortraitCharacterVO();
			c.setName(feature.getFeatureName());
			c.setTgi(feature.getTgi());
			c.setPercent(feature.getPercent());
			c.setStatus(1);
			charList.add(c);
		}
		
		vo.setUninstallPortraitCharactList(charList);
		
		// 3. 卸载阶段统计
		List<UninstallPortraitPhaseVO> phaseList = new ArrayList<>();

		Map<String, List<MktPortrait>> phaseGroups = portraitList.stream()
			.filter(p -> !StringUtils.isEmpty(p.getPhase()))
			.collect(Collectors.groupingBy(MktPortrait::getPhase));
		
		for (Map.Entry<String, List<MktPortrait>> entry : phaseGroups.entrySet()) {
			String phase = entry.getKey();
			ConfigItem phaseConfig = ConfigUtils.getConfigValue("Phase_type", phase);
			List<MktPortrait> phaseData = entry.getValue();
			
			// 计算该阶段的总数量和占比
			int phaseCount = phaseData.stream()
				.mapToInt(p -> p.getPhaseCount() != null ? p.getPhaseCount() : 0)
				.sum();
			
			double phaseRate = 0.0;
			if (totalCount > 0) {
				phaseRate = Math.round((double) phaseCount / totalCount * 10000.0) / 100.0;
			}
			
			UninstallPortraitPhaseVO p = new UninstallPortraitPhaseVO();
			p.setPhase(!StringUtils.isEmpty(phaseConfig.getLabel()) ? phaseConfig.getLabel() : "");
			p.setCount(phaseCount);
			p.setRate(phaseRate);
			phaseList.add(p);
		}
		
		vo.setUninstallPortraitPhaseList(phaseList);
		
		return vo;
	}

	@Override
	public List<UninstallPredictVO> getUninstallPredict(UninstallPredictDTO dto) {
		QueryWrapper<MktPredict> wrapper = new QueryWrapper<>();
		
		if (dto.getType() != null) {
			wrapper.eq("type", dto.getType());
		}
		
		if (!StringUtils.isEmpty(dto.getCycle())) {
			wrapper.eq("stat_cycle", dto.getCycle());
		}
		
		if (!StringUtils.isEmpty(dto.getAppId())) {
			wrapper.eq("app_id", dto.getAppId());
		}
		if (!StringUtils.isEmpty(dto.getChannel())) {
			wrapper.eq("channel", dto.getChannel());
		}
		if (!StringUtils.isEmpty(dto.getVersion())) {
			wrapper.eq("app_version", dto.getVersion());
		}
		
		if (!StringUtils.isEmpty(dto.getStartDate()) && !StringUtils.isEmpty(dto.getEndDate())) {
			wrapper.between("stat_date", dto.getStartDate(), dto.getEndDate());
		}
		
		List<MktPredict> predictList = statPredictMapper.selectList(wrapper);
		
		List<UninstallPredictVO> result = new ArrayList<>();
		
		if (predictList != null && !predictList.isEmpty()) {
			for (MktPredict entity : predictList) {
				UninstallPredictVO vo = new UninstallPredictVO();
				
				if (entity.getPredictTime() != null) {
					vo.setPredictTime(entity.getPredictTime().toString());
				} else {
					LocalDate predictTime = LocalDate.now().with(DayOfWeek.MONDAY);
					vo.setPredictTime(predictTime.toString());
				}
				
				vo.setUninstallCount(entity.getUninstallCount() != null ? entity.getUninstallCount() : 0);
				
				if (entity.getType() != null && entity.getType() == 1) {
					vo.setRecallCount(entity.getUninstallCount() != null ? entity.getUninstallCount() : 0);
				} else {
					vo.setRecallCount(0);
				}
				
				result.add(vo);
			}
		}
		return result;
	}

	@Override
	public List<InstallUninstallRatioVO> getInstallUninstallRatio(InstallUninstallRatioDTO dto) {
		QueryWrapper<MktInstallUninstallRatio> wrapper = new QueryWrapper<>();
		
		if (!StringUtils.isEmpty(dto.getCycle())) {
			wrapper.eq("stat_cycle", dto.getCycle());
		}
		
		if (!StringUtils.isEmpty(dto.getAppId())) {
			wrapper.eq("app_id", dto.getAppId());
		}
		
		if (!StringUtils.isEmpty(dto.getChannel())) {
			wrapper.eq("channel", dto.getChannel());
		}
		
		if (!StringUtils.isEmpty(dto.getVersion())) {
			wrapper.eq("app_version", dto.getVersion());
		}

		
		if (!StringUtils.isEmpty(dto.getStartDate()) && !StringUtils.isEmpty(dto.getEndDate())) {
			wrapper.between("stat_date", dto.getStartDate(), dto.getEndDate());
		}
		
		List<MktInstallUninstallRatio> ratioList = statInstallRatioMapper.selectList(wrapper);
		
		// 按日期分组，每个日期对应多个行业-占比
		Map<Date, List<MktInstallUninstallRatio>> dateGroups = ratioList.stream()
			.collect(Collectors.groupingBy(MktInstallUninstallRatio::getStatDate));
		
		List<InstallUninstallRatioVO> result = new ArrayList<>();
		for (Map.Entry<Date, List<MktInstallUninstallRatio>> entry : dateGroups.entrySet()) {
			Date date = entry.getKey();
			List<MktInstallUninstallRatio> dateData = entry.getValue();
			
			InstallUninstallRatioVO vo = new InstallUninstallRatioVO();
			vo.setDate(date);
			
			// 构建该日期下的所有行业-占比数据
			List<Map<String, Double>> typeList = new ArrayList<>();
			for (MktInstallUninstallRatio entity : dateData) {
				Map<String, Double> typeMap = new HashMap<>();
				
				// 获取行业类型标签
				String industryLabel = "未知类型";
				if (entity.getIndustryType() != null) {
					ConfigItem configValue = ConfigUtils.getConfigValue("Industry_type", String.valueOf(entity.getIndustryType()));
					industryLabel = configValue != null ? configValue.getLabel() : "未知类型";
				}
				
				// 设置占比
				Double rate = entity.getRate() != null ? entity.getRate() : 0.0;
				typeMap.put(industryLabel, rate);
				typeList.add(typeMap);
			}
			
			vo.setType(typeList);
			result.add(vo);
		}
		
		return result;
	}

	@Override
	public Page<InstallUninstallRatioVO> getInstallUninstallRatioDetail(InstallUninstallRatioDTO dto) {
		// 分页参数
		int pageNum = dto.getPageNum() == null ? 1 : dto.getPageNum();
		int pageSize = dto.getPageSize() == null ? 10 : dto.getPageSize();
		
		List<InstallUninstallRatioVO> allData = getInstallUninstallRatio(dto);
		
		// 使用PageUtils工具类处理分页
		return PageUtils.buildPage(allData, pageNum, pageSize);
	}
} 
