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<Long> userIds = company == null ? List.of(userId) :
                user.getCompany()
                        .getUsers()
                        .stream()
                        .map(User::getId).toList();

        long totalSearches = taskRepository.countByUserId(userIds);
        List<Object[]> 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<GlobalSearchTask> 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<GlobalSearchStatisticsResponse.SearchStatDto> recentSearchDtos = new ArrayList<>();

        for (GlobalSearchTask task : recentTasks) {
            List<GlobalSearchResult> globalSearchResults = resultRepository.findByTaskId(task.getTaskId());
            List<String> 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();
    }
}
