package com.example.demo.service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.demo.model.UserActivityStats;
import com.example.demo.repository.OrderRepository;
import com.example.demo.repository.TaskQueueRepository;
import com.example.demo.repository.UserActivityStatsRepository;
import com.example.demo.repository.UserRepository;

/**
 * 用户活跃度统计服务
 * 负责计算和保存日活用户数据
 * 
 * 日活用户定义：当天有以下任一行为的不同用户数
 * 1. 有API请求活动（通过lastActiveTime判断）
 * 2. 有登录行为（通过lastLoginAt判断）
 * 3. 有订单操作
 * 4. 有任务操作
 */
@Service
public class UserActivityStatsService {

    private static final Logger logger = LoggerFactory.getLogger(UserActivityStatsService.class);

    @Autowired
    private UserActivityStatsRepository userActivityStatsRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private TaskQueueRepository taskQueueRepository;

    /**
     * 计算并保存指定日期的日活用户数
     * 
     * @param date 要统计的日期
     * @param forceUpdate 是否强制更新（用于当天数据的实时更新）
     */
    @Transactional
    public void calculateAndSaveDailyActiveUsers(LocalDate date, boolean forceUpdate) {
        try {
            // 检查是否已经存在该日期的统计数据
            List<UserActivityStats> existingList = userActivityStatsRepository.findByActivityDateBetween(date, date);
            Optional<UserActivityStats> existing = existingList.stream()
                .filter(stats -> stats.getActivityDate().equals(date))
                .findFirst();
            
            // 如果数据已存在且不是强制更新，则跳过
            if (existing.isPresent() && !forceUpdate) {
                logger.debug("日期 {} 的统计数据已存在，跳过计算", date);
                return;
            }

            LocalDateTime startOfDay = date.atStartOfDay();
            LocalDateTime endOfDay = date.atTime(23, 59, 59);

            Set<Long> activeUserIds = new java.util.HashSet<>();

            // 方法1：统计当天有API活动的用户（通过lastActiveTime判断）
            userRepository.findAll().stream()
                .filter(user -> user.getLastActiveTime() != null &&
                        !user.getLastActiveTime().isBefore(startOfDay) &&
                        !user.getLastActiveTime().isAfter(endOfDay))
                .forEach(user -> activeUserIds.add(user.getId()));

            // 方法2：统计当天登录的用户
            userRepository.findAll().stream()
                .filter(user -> user.getLastLoginAt() != null &&
                        !user.getLastLoginAt().isBefore(startOfDay) &&
                        !user.getLastLoginAt().isAfter(endOfDay))
                .forEach(user -> activeUserIds.add(user.getId()));

            // 方法3：统计当天有订单的用户
            orderRepository.findAll().stream()
                .filter(order -> order.getCreatedAt() != null &&
                        !order.getCreatedAt().isBefore(startOfDay) &&
                        !order.getCreatedAt().isAfter(endOfDay))
                .filter(order -> order.getUser() != null)
                .forEach(order -> activeUserIds.add(order.getUser().getId()));

            // 方法4：统计当天有任务操作的用户
            Set<String> activeUsernames = taskQueueRepository.findAll().stream()
                .filter(task -> task.getCreatedAt() != null &&
                        !task.getCreatedAt().isBefore(startOfDay) &&
                        !task.getCreatedAt().isAfter(endOfDay))
                .map(task -> task.getUsername())
                .filter(username -> username != null && !username.isEmpty())
                .collect(Collectors.toSet());
            
            activeUsernames.forEach(username -> {
                userRepository.findByUsername(username).ifPresent(user -> {
                    activeUserIds.add(user.getId());
                });
            });

            // 日活用户数
            int dailyActiveUsers = activeUserIds.size();

            // 统计当天新增用户数
            long newUsers = userRepository.findAll().stream()
                .filter(user -> user.getCreatedAt() != null &&
                        !user.getCreatedAt().isBefore(startOfDay) &&
                        !user.getCreatedAt().isAfter(endOfDay))
                .count();

            // 创建或更新统计数据
            UserActivityStats stats = existing.orElse(new UserActivityStats());
            stats.setActivityDate(date);
            stats.setDailyActiveUsers(dailyActiveUsers);
            stats.setNewUsers((int) newUsers);
            stats.setReturningUsers(Math.max(0, dailyActiveUsers - (int) newUsers));
            
            // 计算月活用户（当月至少活跃一次的用户数）
            LocalDate monthStart = date.withDayOfMonth(1);
            LocalDateTime monthStartTime = monthStart.atStartOfDay();
            
            Set<Long> monthlyActiveUserIds = new java.util.HashSet<>();
            
            // 统计当月有活动的用户
            userRepository.findAll().stream()
                .filter(user -> {
                    // 检查lastActiveTime
                    if (user.getLastActiveTime() != null &&
                        !user.getLastActiveTime().isBefore(monthStartTime) &&
                        !user.getLastActiveTime().isAfter(endOfDay)) {
                        return true;
                    }
                    // 检查lastLoginAt
                    if (user.getLastLoginAt() != null &&
                        !user.getLastLoginAt().isBefore(monthStartTime) &&
                        !user.getLastLoginAt().isAfter(endOfDay)) {
                        return true;
                    }
                    return false;
                })
                .forEach(user -> monthlyActiveUserIds.add(user.getId()));
            
            stats.setMonthlyActiveUsers(monthlyActiveUserIds.size());

            userActivityStatsRepository.save(stats);
            
            logger.info("日期 {} 的日活用户统计完成: 日活={}, 新增={}, 月活={}", 
                    date, dailyActiveUsers, newUsers, monthlyActiveUserIds.size());

        } catch (Exception e) {
            logger.error("计算日期 {} 的日活用户统计失败", date, e);
        }
    }
    
    /**
     * 计算并保存指定日期的日活用户数（默认不强制更新）
     */
    @Transactional
    public void calculateAndSaveDailyActiveUsers(LocalDate date) {
        calculateAndSaveDailyActiveUsers(date, false);
    }

    /**
     * 定时任务：每天凌晨2点计算前一天的日活用户数据
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void calculateYesterdayDailyActiveUsers() {
        LocalDate yesterday = LocalDate.now().minusDays(1);
        logger.info("开始计算日期 {} 的日活用户统计", yesterday);
        calculateAndSaveDailyActiveUsers(yesterday, true); // 强制更新确保数据准确
    }

    /**
     * 定时任务：每小时更新当天的日活用户数据（实时更新）
     */
    @Scheduled(cron = "0 0 * * * ?")
    public void updateTodayDailyActiveUsers() {
        LocalDate today = LocalDate.now();
        logger.info("实时更新日期 {} 的日活用户统计", today);
        calculateAndSaveDailyActiveUsers(today, true); // 强制更新当天数据
    }

    /**
     * 手动触发：计算指定日期的日活用户数据
     */
    public void calculateDailyActiveUsersForDate(LocalDate date) {
        calculateAndSaveDailyActiveUsers(date, true);
    }

    /**
     * 批量计算：计算最近N天的日活用户数据（强制更新）
     */
    @Transactional
    public void calculateDailyActiveUsersForRecentDays(int days) {
        LocalDate today = LocalDate.now();
        for (int i = 0; i < days; i++) {
            LocalDate date = today.minusDays(i);
            calculateAndSaveDailyActiveUsers(date, true);
        }
        logger.info("完成最近 {} 天的日活用户统计", days);
    }
    
    /**
     * 获取今日实时日活用户数（不保存，仅查询）
     */
    public int getTodayActiveUsersCount() {
        LocalDate today = LocalDate.now();
        LocalDateTime startOfDay = today.atStartOfDay();
        LocalDateTime now = LocalDateTime.now();
        
        Set<Long> activeUserIds = new java.util.HashSet<>();
        
        // 统计今天有活动的用户
        userRepository.findAll().stream()
            .filter(user -> {
                if (user.getLastActiveTime() != null &&
                    !user.getLastActiveTime().isBefore(startOfDay) &&
                    !user.getLastActiveTime().isAfter(now)) {
                    return true;
                }
                if (user.getLastLoginAt() != null &&
                    !user.getLastLoginAt().isBefore(startOfDay) &&
                    !user.getLastLoginAt().isAfter(now)) {
                    return true;
                }
                return false;
            })
            .forEach(user -> activeUserIds.add(user.getId()));
        
        return activeUserIds.size();
    }
}

