package ru.soune.nocopy.service.search; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.soune.nocopy.dto.search.GlobalSearchStatisticsResponse; import ru.soune.nocopy.entity.company.Company; import ru.soune.nocopy.entity.search.GlobalSearchResult; import ru.soune.nocopy.entity.search.GlobalSearchTask; import ru.soune.nocopy.entity.user.User; import ru.soune.nocopy.repository.*; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @Slf4j @Service @RequiredArgsConstructor public class GlobalSearchStatisticsService { private final GlobalSearchTaskRepository taskRepository; private final GlobalSearchResultRepository resultRepository; private final ViolationRepository violationRepository; private final UserRepository userRepository; @Transactional(readOnly = true) public GlobalSearchStatisticsResponse getStatistics(Long userId, Integer limit, Integer days) { User user = userRepository.findById(userId).orElseThrow(); Company company = user.getCompany(); List userIds = company == null ? List.of(userId) : user.getCompany() .getUsers() .stream() .map(User::getId).toList(); long totalSearches = taskRepository.countByUserId(userIds); List statusCounts = taskRepository.countByStatusAndUserId(userIds); GlobalSearchStatisticsResponse.StatusCountDto statusCountDto = GlobalSearchStatisticsResponse.StatusCountDto.builder() .processing(0) .completed(0) .failed(0) .total(totalSearches) .build(); for (Object[] row : statusCounts) { String status = (String) row[0]; Long count = (Long) row[1]; if ("PROCESSING".equalsIgnoreCase(status)) { statusCountDto.setProcessing(count); } else if ("COMPLETED".equalsIgnoreCase(status) || "SUCCESS".equalsIgnoreCase(status)) { statusCountDto.setCompleted(statusCountDto.getCompleted() + count); } else if ("FAILED".equalsIgnoreCase(status) || "TIMEOUT".equalsIgnoreCase(status)) { statusCountDto.setFailed(statusCountDto.getFailed() + count); } } List recentTasks; if (days != null && days > 0) { LocalDateTime fromDate = LocalDateTime.now().minusDays(days); recentTasks = taskRepository.findByUserIdAndCreatedAtAfterOrderByCreatedAtDesc(userId, fromDate); if (limit != null && limit > 0 && recentTasks.size() > limit) { recentTasks = recentTasks.subList(0, limit); } } else { org.springframework.data.domain.Pageable pageable = org.springframework.data.domain.PageRequest.of(0, limit != null ? limit : 10); recentTasks = taskRepository.findTopByUserIdOrderByCreatedAtDesc(userId, pageable); } List recentSearchDtos = new ArrayList<>(); for (GlobalSearchTask task : recentTasks) { List globalSearchResults = resultRepository.findByTaskId(task.getTaskId()); List fileIds = globalSearchResults.stream() .map(GlobalSearchResult::getFileId) .toList(); GlobalSearchStatisticsResponse.SearchStatDto searchStatDto = GlobalSearchStatisticsResponse.SearchStatDto.fromEntity(task, violationRepository.countByFileEntityIdIn(fileIds), fileIds); recentSearchDtos.add(searchStatDto); } return GlobalSearchStatisticsResponse.builder() .totalSearches(totalSearches) .searchesByStatus(statusCountDto) .recentSearches(recentSearchDtos) .build(); } }