package dev.lions.unionflow.server.resource;

import dev.lions.unionflow.server.api.dto.audit.response.AuditTrailOperationResponse;
import dev.lions.unionflow.server.service.audit.AuditTrailQueryService;
import io.quarkus.security.Authenticated;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * Endpoints REST de lecture de l'audit trail enrichi (Sprint 1, exposé Sprint 10).
 *
 * <p>Cible : compliance officer / contrôleur interne / SUPER_ADMIN. Seule la lecture
 * est exposée — les écritures sont produites automatiquement par les services métier
 * via {@code AuditTrailService}.
 *
 * @since 2026-04-25 (Sprint 10)
 */
@Path("/api/audit-trail")
@Produces(MediaType.APPLICATION_JSON)
@Authenticated
public class AuditTrailOperationResource {

  @Inject AuditTrailQueryService queryService;
  @Inject dev.lions.unionflow.server.service.audit.AuditTrailExportService exportService;

  @GET
  @Path("/by-user/{userId}")
  @RolesAllowed({"COMPLIANCE_OFFICER", "CONTROLEUR_INTERNE", "SUPER_ADMIN"})
  public List<AuditTrailOperationResponse> parUtilisateur(
      @PathParam("userId") UUID userId,
      @QueryParam("from") String from,
      @QueryParam("to") String to) {
    LocalDateTime fromDt = parseDateTime(from, LocalDateTime.now().minusDays(30));
    LocalDateTime toDt = parseDateTime(to, LocalDateTime.now());
    return queryService.rechercherParUtilisateur(userId, fromDt, toDt);
  }

  @GET
  @Path("/by-entity/{type}/{id}")
  @RolesAllowed({"COMPLIANCE_OFFICER", "CONTROLEUR_INTERNE", "SUPER_ADMIN"})
  public List<AuditTrailOperationResponse> historique(
      @PathParam("type") String entityType,
      @PathParam("id") UUID entityId) {
    return queryService.historiqueEntite(entityType, entityId);
  }

  @GET
  @Path("/by-organisation/{orgId}")
  @RolesAllowed({"COMPLIANCE_OFFICER", "CONTROLEUR_INTERNE", "ADMIN_ORGANISATION", "SUPER_ADMIN"})
  public List<AuditTrailOperationResponse> parOrganisation(@PathParam("orgId") UUID orgId) {
    return queryService.rechercherParOrganisation(orgId);
  }

  @GET
  @Path("/sod-violations")
  @RolesAllowed({"COMPLIANCE_OFFICER", "CONTROLEUR_INTERNE", "SUPER_ADMIN"})
  public List<AuditTrailOperationResponse> violationsSod() {
    return queryService.violationsSod();
  }

  @GET
  @Path("/financial/{orgId}")
  @RolesAllowed({"COMPLIANCE_OFFICER", "CONTROLEUR_INTERNE", "TRESORIER", "SUPER_ADMIN"})
  public List<AuditTrailOperationResponse> operationsFinancieres(
      @PathParam("orgId") UUID orgId,
      @QueryParam("from") String from,
      @QueryParam("to") String to) {
    LocalDateTime fromDt = parseDateTime(from, LocalDateTime.now().minusDays(90));
    LocalDateTime toDt = parseDateTime(to, LocalDateTime.now());
    return queryService.operationsFinancieres(orgId, fromDt, toDt);
  }

  /**
   * Live Activity Feed (Sprint 15) — N opérations les plus récentes (transparency).
   *
   * <p>Scopes :
   * <ul>
   *   <li>ALL — toutes orgs (restreint compliance/contrôleurs/super-admin)</li>
   *   <li>ORG — organisation indiquée (admin org / président / officers)</li>
   *   <li>SELF (défaut) — opérations de l'utilisateur indiqué (n'importe quel rôle peut voir les siennes)</li>
   * </ul>
   *
   * <p>Limit clampé à [1, 500] côté repository (sécurité contre DoS).
   */
  @GET
  @Path("/recent")
  @RolesAllowed({"COMPLIANCE_OFFICER", "CONTROLEUR_INTERNE", "ADMIN_ORGANISATION",
      "PRESIDENT", "TRESORIER", "MEMBRE", "SUPER_ADMIN"})
  public List<AuditTrailOperationResponse> recent(
      @QueryParam("scope") @jakarta.ws.rs.DefaultValue("SELF") String scope,
      @QueryParam("orgId") UUID orgId,
      @QueryParam("userId") UUID userId,
      @QueryParam("limit") @jakarta.ws.rs.DefaultValue("50") int limit) {
    return queryService.listerRecentes(scope, orgId, userId, limit);
  }

  /**
   * Export massif audit (Sprint 16.B) — formats CSV / XLSX / PDF pour BCEAO/ARTCI/CENTIF.
   */
  @GET
  @Path("/export")
  @jakarta.ws.rs.Produces("application/octet-stream")
  @RolesAllowed({"COMPLIANCE_OFFICER", "CONTROLEUR_INTERNE", "SUPER_ADMIN"})
  public jakarta.ws.rs.core.Response export(
      @QueryParam("format") @jakarta.ws.rs.DefaultValue("csv") String format,
      @QueryParam("scope") @jakarta.ws.rs.DefaultValue("ALL") String scope,
      @QueryParam("orgId") UUID orgId,
      @QueryParam("userId") UUID userId,
      @QueryParam("limit") @jakarta.ws.rs.DefaultValue("500") int limit) {
    String fmt = format == null ? "csv" : format.toLowerCase();
    byte[] payload;
    String mediaType;
    String extension;
    switch (fmt) {
      case "xlsx" -> {
        payload = exportService.exportXlsx(scope, orgId, userId, limit);
        mediaType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        extension = "xlsx";
      }
      case "pdf" -> {
        payload = exportService.exportPdf(scope, orgId, userId, limit);
        mediaType = "application/pdf";
        extension = "pdf";
      }
      default -> {
        payload = exportService.exportCsv(scope, orgId, userId, limit);
        mediaType = "text/csv";
        extension = "csv";
      }
    }
    String filename = String.format("audit-trail-%s-%s.%s",
        scope.toLowerCase(), java.time.LocalDate.now(), extension);
    return jakarta.ws.rs.core.Response.ok(payload, mediaType)
        .header("Content-Disposition", "attachment; filename=\"" + filename + "\"")
        .build();
  }

  private LocalDateTime parseDateTime(String input, LocalDateTime fallback) {
    if (input == null || input.isBlank()) return fallback;
    try {
      return LocalDateTime.parse(input);
    } catch (Exception e) {
      return fallback;
    }
  }
}
