package org.jeecg.modules.adweb.dmp.service.impl;

import static org.jeecg.modules.adweb.dmp.vo.report.SiteOverviewStatsVO.DailyStatsVO;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.adweb.common.util.DateUtil;
import org.jeecg.modules.adweb.common.util.NumberUtil;
import org.jeecg.modules.adweb.dmp.entity.GADailyReport;
import org.jeecg.modules.adweb.dmp.mapper.GADailyReportMapper;
import org.jeecg.modules.adweb.dmp.service.IGADailyReportService;
import org.jeecg.modules.adweb.dmp.vo.report.PeriodicStatsVO;
import org.jeecg.modules.adweb.enquiry.mapper.AdwebEnquiryMapper;
import org.jeecg.modules.adweb.site.entity.AdwebSite;
import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
import org.jeecg.modules.redis.CacheConfig;
import org.jeecg.modules.redis.TTLCacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: adweb_dmp_ga_daily_report @Author: jeecg-boot @Date: 2024-11-04 @Version: V1.0
 */
@Service
public class GADailyReportServiceImpl extends ServiceImpl<GADailyReportMapper, GADailyReport>
        implements IGADailyReportService {

    @Autowired private IAdwebSiteService adwebSiteService;

    @Autowired private GADailyReportMapper gaDailyReportMapper;

    @Autowired private AdwebEnquiryMapper adwebEnquiryMapper;

    /**
     * 查询指定时间区间内的{@link DailyStatsVO}
     *
     * <p>如数据库中某天数据缺失，需填充空数据
     *
     * <p>填充每日询盘数据
     */
    @Override
    @Cacheable(
            cacheManager = CacheConfig.TTL_CACHE_MANAGER,
            cacheNames =
                    "dmp:getDailyStats" + TTLCacheManager.TTL_SPLITTER + 60 * 10) // Redis TTL为10分钟
    public List<DailyStatsVO> getDailyStats(String siteCode, Date start, Date end) {
        Map<String, DailyStatsVO> dailyStatsVOs = Maps.newHashMap();

        // 0. 起止日期为空时，设置默认区间 - start = 网站发布日期 & end = 今天
        if (start == null || end == null) {
            AdwebSite adwebSite = adwebSiteService.getSiteByCode(siteCode);
            start =
                    DateUtil.getTodayZeroTime(
                            Optional.ofNullable(adwebSite.getIssueTime())
                                    .orElse(adwebSite.getCtime()));
            end = DateUtil.getTodayZeroTime(new Date());
        }

        // 1. VO数据填充
        List<GADailyReport> gaDailyReports =
                this.list(
                        new LambdaQueryWrapper<GADailyReport>()
                                .eq(GADailyReport::getSiteCode, siteCode)
                                .ge(GADailyReport::getDate, start)
                                .le(GADailyReport::getDate, end)
                                .orderByAsc(GADailyReport::getDate));

        for (GADailyReport gaDailyReport : gaDailyReports) {
            DailyStatsVO dailyStatsVO = new DailyStatsVO();
            String date = DateUtils.date2Str(gaDailyReport.getDate(), DateUtils.date_sdf.get());
            dailyStatsVO.setDate(date);
            dailyStatsVO.setTotalUsers(gaDailyReport.getTotalUsers());
            dailyStatsVO.setSessions(gaDailyReport.getSessions());
            dailyStatsVO.setBounceRate(gaDailyReport.getBounceRate());
            dailyStatsVO.setAvgSessionDuration(gaDailyReport.getAvgSessionDuration());
            dailyStatsVO.setPageViews(gaDailyReport.getPageViews());
            dailyStatsVO.setPageViewsPerSession(gaDailyReport.getPageViewsPerSession());

            dailyStatsVOs.put(date, dailyStatsVO);
        }

        // 2. 缺失日期补充
        Set<String> absentDays =
                Sets.difference(
                        DateUtil.getAllDaysBetween(start, end).stream()
                                .map(date -> DateUtils.date2Str(date, DateUtils.date_sdf.get()))
                                .collect(Collectors.toSet()),
                        dailyStatsVOs.keySet());
        absentDays.forEach(
                date -> {
                    DailyStatsVO dailyStatsVO = new DailyStatsVO();
                    dailyStatsVO.setDate(date); // 其它数值字段设置为默认值
                    dailyStatsVOs.put(date, dailyStatsVO);
                });

        // 3. 询盘数据补充
        List<ImmutableTriple<String, Long, Long>> enquiryDailyCounts =
                adwebEnquiryMapper.getEnquiryDailyCounts(siteCode, start, end);
        for (ImmutableTriple<String, Long, Long> enquiryDailyCount : enquiryDailyCounts) {
            if (!dailyStatsVOs.containsKey(enquiryDailyCount.getLeft())) {
                continue;
            }

            DailyStatsVO dailyStatsVO = dailyStatsVOs.get(enquiryDailyCount.getLeft());
            dailyStatsVO.setEnquires(enquiryDailyCount.getMiddle().intValue());
            dailyStatsVO.setUnreadEnquires(enquiryDailyCount.getRight().intValue());
        }

        // 3. 根据日期排序并返回
        return dailyStatsVOs.values().stream()
                .sorted(Comparator.comparing(DailyStatsVO::getDate)) // 按日期升序排序
                .collect(Collectors.toList()); // 使用toList()方法返回UnmodifiableList，导致Redis类型解析异常
    }

    /**
     * 查询分时间段的{@link PeriodicStatsVO} - 今天，昨天，本周，上周，本月，上月，全部
     *
     * <p>填充各时间段询盘数据
     */
    @Override
    @Cacheable(
            cacheManager = CacheConfig.TTL_CACHE_MANAGER,
            cacheNames =
                    "dmp:getPeriodicStats"
                            + TTLCacheManager.TTL_SPLITTER
                            + 60 * 10) // Redis TTL为10分钟
    public List<PeriodicStatsVO> getPeriodicStats(String siteCode) {
        // 1. 查询GA统计数据 - UV，PV等
        Map<String, PeriodicStatsVO> periodicStatsVOs =
                gaDailyReportMapper.getPeriodicStats(siteCode).stream()
                        .collect(
                                Collectors.toMap(
                                        PeriodicStatsVO::getPeriod,
                                        Function.identity(),
                                        (x, y) -> y,
                                        LinkedHashMap::new)); // 使用LinkedHashMap保持原查询顺序

        // 2. 询盘数据补充
        List<ImmutablePair<String, Long>> enquiryPeriodicCounts =
                adwebEnquiryMapper.getEnquiryPeriodicCounts(siteCode);
        for (ImmutablePair<String, Long> enquiryPeriodicCount : enquiryPeriodicCounts) {
            if (!periodicStatsVOs.containsKey(enquiryPeriodicCount.getKey())) {
                continue;
            }

            PeriodicStatsVO periodicStatsVO = periodicStatsVOs.get(enquiryPeriodicCount.getKey());
            periodicStatsVO.setEnquires(enquiryPeriodicCount.getValue().intValue());
            periodicStatsVO.setEnquiryConversionRate(
                    NumberUtil.formatPercentage(
                            NumberUtil.safeDivide(
                                    periodicStatsVO.getEnquires(), periodicStatsVO.getTotalUsers()),
                            2));
        }

        return periodicStatsVOs.values().stream()
                .collect(Collectors.toList()); // 使用toList()方法返回UnmodifiableList，导致Redis类型解析异常
    }
}
