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

import dev.lions.unionflow.server.api.dto.notification.request.CreateNotificationRequest;
import dev.lions.unionflow.server.security.AuditOperationLoggedEvent;
import dev.lions.unionflow.server.service.NotificationService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.event.TransactionPhase;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;

/**
 * Notifications transparency (Sprint 16.C) — observe les events audit et notifie l'utilisateur
 * concerné par les opérations sensibles.
 *
 * <p>Filtre selon {@link AuditOperationLoggedEvent#estSensible()} : opérations financières,
 * suppressions, validations, exports, ou violations SoD.
 *
 * <p>Observe en {@code AFTER_SUCCESS} pour ne notifier que si la transaction de l'audit
 * a réussi. Fail-soft : un échec de notification ne propage jamais d'erreur.
 *
 * @since 2026-04-25 (Sprint 16.C — transparency)
 */
@ApplicationScoped
public class AuditNotificationService {

  private static final Logger LOG = Logger.getLogger(AuditNotificationService.class);

  @Inject NotificationService notificationService;

  /**
   * Observe l'événement après commit transactionnel — la notification ne part que si
   * l'écriture audit a effectivement été persistée.
   */
  public void onAuditOperation(@Observes(during = TransactionPhase.AFTER_SUCCESS)
                                AuditOperationLoggedEvent event) {
    if (event == null || !event.estSensible() || event.userId() == null) return;

    try {
      String sujet = sujetPourEvent(event);
      String corps = corpsPourEvent(event);

      CreateNotificationRequest req = CreateNotificationRequest.builder()
          .typeNotification("APP")
          .priorite(prioritePourEvent(event))
          .sujet(sujet)
          .corps(corps)
          .membreId(event.userId())
          .organisationId(event.organisationActiveId())
          .build();

      notificationService.creerNotification(req);
      LOG.debugf("Notification audit transparency émise pour user=%s action=%s",
          event.userId(), event.actionType());
    } catch (Exception e) {
      // Fail-soft : ne jamais bloquer l'audit principal
      LOG.warnf("Notification audit échouée pour event %s : %s",
          event.operationId(), e.getMessage());
    }
  }

  String sujetPourEvent(AuditOperationLoggedEvent e) {
    if (Boolean.FALSE.equals(e.sodCheckPassed())) {
      return "⚠ Violation SoD détectée — " + e.entityType();
    }
    return switch (e.actionType()) {
      case "DELETE" -> "Suppression — " + e.entityType();
      case "PAYMENT_INITIATED" -> "Paiement initié";
      case "PAYMENT_CONFIRMED" -> "Paiement confirmé";
      case "PAYMENT_FAILED" -> "⚠ Paiement échoué";
      case "BUDGET_APPROVED" -> "Budget approuvé";
      case "AID_REQUEST_APPROVED" -> "Demande d'aide approuvée";
      case "EXPORT" -> "Export effectué";
      case "VALIDATE" -> "Validation — " + e.entityType();
      default -> "Opération sensible — " + e.entityType();
    };
  }

  String corpsPourEvent(AuditOperationLoggedEvent e) {
    StringBuilder sb = new StringBuilder();
    if (e.description() != null && !e.description().isBlank()) {
      sb.append(e.description()).append("\n\n");
    }
    sb.append("Acteur : ").append(e.userEmail() == null ? "—" : e.userEmail()).append('\n');
    sb.append("Action : ").append(e.actionType()).append('\n');
    sb.append("Entité : ").append(e.entityType()).append('\n');
    if (e.entityId() != null) {
      sb.append("ID : ").append(e.entityId()).append('\n');
    }
    sb.append("Quand : ").append(e.operationAt());
    if (Boolean.FALSE.equals(e.sodCheckPassed())) {
      sb.append("\n\n⚠ Cette opération a déclenché une alerte de séparation des pouvoirs.");
    }
    return sb.toString();
  }

  String prioritePourEvent(AuditOperationLoggedEvent e) {
    if (Boolean.FALSE.equals(e.sodCheckPassed())) return "HAUTE";
    return switch (e.actionType()) {
      case "PAYMENT_FAILED", "DELETE" -> "HAUTE";
      case "PAYMENT_CONFIRMED", "BUDGET_APPROVED", "AID_REQUEST_APPROVED" -> "NORMALE";
      default -> "BASSE";
    };
  }
}
