package dev.lions.unionflow.server.service.audit;

import dev.lions.unionflow.server.api.dto.audit.response.AuditTrailOperationResponse;
import dev.lions.unionflow.server.entity.AuditTrailOperation;
import dev.lions.unionflow.server.repository.AuditTrailOperationRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * Service de lecture (CQRS read-side) de l'audit trail enrichi.
 *
 * <p>Distinct de {@code AuditTrailService} (write-side dans le package security) qui
 * écrit les entrées d'audit. Ici on ne fait QUE lire et mapper vers DTO. Single
 * Responsibility = consultation côté compliance officer / contrôleur interne.
 *
 * @since 2026-04-25 (Sprint 10)
 */
@ApplicationScoped
public class AuditTrailQueryService {

  @Inject AuditTrailOperationRepository repository;

  /** Opérations d'un utilisateur dans une fenêtre temporelle. */
  public List<AuditTrailOperationResponse> rechercherParUtilisateur(
      UUID userId, LocalDateTime from, LocalDateTime to) {
    return repository.findByUserBetween(userId, from, to).stream().map(this::toResponse).toList();
  }

  /** Historique d'une entité (toutes opérations CRUD/VALIDATE/EXPORT). */
  public List<AuditTrailOperationResponse> historiqueEntite(String entityType, UUID entityId) {
    return repository.findByEntity(entityType, entityId).stream().map(this::toResponse).toList();
  }

  /** Opérations dans le contexte d'une organisation. */
  public List<AuditTrailOperationResponse> rechercherParOrganisation(UUID organisationActiveId) {
    return repository.findByOrganisationActive(organisationActiveId).stream()
        .map(this::toResponse).toList();
  }

  /** Toutes les violations de séparation des pouvoirs détectées. */
  public List<AuditTrailOperationResponse> violationsSod() {
    return repository.findSoDViolations().stream().map(this::toResponse).toList();
  }

  /** Opérations financières d'une organisation sur une période — utile reporting AIRMS. */
  public List<AuditTrailOperationResponse> operationsFinancieres(
      UUID organisationId, LocalDateTime from, LocalDateTime to) {
    return repository.findFinancialOperations(organisationId, from, to).stream()
        .map(this::toResponse).toList();
  }

  /**
   * Live Feed (Sprint 15) — N opérations les plus récentes selon le scope demandé.
   *
   * @param scope ALL (toutes orgs — restreint COMPLIANCE_OFFICER/CONTROLEUR_INTERNE/SUPER_ADMIN),
   *              ORG (organisation passée), SELF (utilisateur passé)
   * @param organisationId requis pour scope=ORG
   * @param userId requis pour scope=SELF
   * @param limit clampé à [1, 500]
   */
  public List<AuditTrailOperationResponse> listerRecentes(
      String scope, UUID organisationId, UUID userId, int limit) {
    String s = scope == null ? "ALL" : scope.toUpperCase();
    return switch (s) {
      case "ORG" -> organisationId == null
          ? java.util.List.of()
          : repository.findRecentByOrganisation(organisationId, limit)
              .stream().map(this::toResponse).toList();
      case "SELF" -> userId == null
          ? java.util.List.of()
          : repository.findRecentByUser(userId, limit)
              .stream().map(this::toResponse).toList();
      default -> repository.findRecent(limit)
          .stream().map(this::toResponse).toList();
    };
  }

  // ────────────────────────────────────────────────────────────
  // Mapping Entity ↔ DTO
  // ────────────────────────────────────────────────────────────

  AuditTrailOperationResponse toResponse(AuditTrailOperation e) {
    return AuditTrailOperationResponse.builder()
        .id(e.getId())
        .userId(e.getUserId())
        .userEmail(e.getUserEmail())
        .roleActif(e.getRoleActif())
        .organisationActiveId(e.getOrganisationActiveId())
        .actionType(e.getActionType())
        .entityType(e.getEntityType())
        .entityId(e.getEntityId())
        .description(e.getDescription())
        .ipAddress(e.getIpAddress())
        .userAgent(e.getUserAgent())
        .requestId(e.getRequestId())
        .payloadAvant(e.getPayloadAvant())
        .payloadApres(e.getPayloadApres())
        .metadata(e.getMetadata())
        .sodCheckPassed(e.getSodCheckPassed())
        .sodViolations(e.getSodViolations())
        .operationAt(e.getOperationAt())
        .build();
  }
}
