package org.raddatz.familienarchiv.audit;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.time.OffsetDateTime;
import java.util.*;

import static org.raddatz.familienarchiv.audit.AuditKind.GROUP_MEMBERSHIP_CHANGED;
import static org.raddatz.familienarchiv.audit.AuditKind.USER_CREATED;
import static org.raddatz.familienarchiv.audit.AuditKind.USER_DELETED;

@Service
@RequiredArgsConstructor
public class AuditLogQueryService {

    private final AuditLogQueryRepository queryRepository;

    public Optional<UUID> findMostRecentDocumentForUser(UUID userId) {
        return queryRepository.findMostRecentDocumentIdByActor(userId);
    }

    public List<ActivityFeedRow> findActivityFeed(UUID currentUserId, int limit) {
        return findActivityFeed(currentUserId, limit, AuditKind.ROLLUP_ELIGIBLE);
    }

    public List<ActivityFeedRow> findActivityFeed(UUID currentUserId, int limit, Set<AuditKind> kinds) {
        List<String> kindNames = kinds.stream().map(Enum::name).toList();
        return queryRepository.findRolledUpActivityFeed(currentUserId.toString(), limit, kindNames);
    }

    public PulseStatsRow getPulseStats(OffsetDateTime weekStart, UUID userId) {
        return queryRepository.getPulseStats(weekStart, userId.toString());
    }

    public Map<UUID, UUID> findMostRecentActorPerDocument(List<UUID> documentIds, String kind) {
        if (documentIds.isEmpty()) return Map.of();
        List<Object[]> rows = queryRepository.findMostRecentActorPerDocument(documentIds, kind);
        Map<UUID, UUID> result = new LinkedHashMap<>();
        for (Object[] row : rows) {
            UUID docId = (UUID) row[0];
            UUID actorId = (UUID) row[1];
            result.put(docId, actorId);
        }
        return result;
    }

    public Map<UUID, List<ActivityActorDTO>> findContributorsPerDocument(List<UUID> documentIds) {
        if (documentIds.isEmpty()) return Map.of();
        return toContributorMap(queryRepository.findContributorsPerDocument(documentIds));
    }

    public Map<UUID, List<ActivityActorDTO>> findRecentContributorsPerDocument(List<UUID> documentIds) {
        if (documentIds.isEmpty()) return Map.of();
        return toContributorMap(queryRepository.findRecentContributorsForDocuments(documentIds));
    }

    public List<AuditLog> findRecentUserManagementEvents(int limit) {
        PageRequest page = PageRequest.of(0, limit, Sort.by("happenedAt").descending());
        return queryRepository.findByKindIn(Set.of(USER_CREATED, USER_DELETED, GROUP_MEMBERSHIP_CHANGED), page).getContent();
    }

    private Map<UUID, List<ActivityActorDTO>> toContributorMap(List<ContributorRow> rows) {
        Map<UUID, List<ActivityActorDTO>> result = new LinkedHashMap<>();
        for (ContributorRow row : rows) {
            result.computeIfAbsent(row.getDocumentId(), k -> new ArrayList<>())
                  .add(new ActivityActorDTO(row.getActorInitials(), row.getActorColor(), row.getActorName()));
        }
        return result;
    }
}
