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

import dev.lions.unionflow.server.entity.FormationLbcFt;
import dev.lions.unionflow.server.entity.ParticipationFormationLbcFt;
import dev.lions.unionflow.server.repository.FormationLbcFtRepository;
import dev.lions.unionflow.server.repository.ParticipationFormationLbcFtRepository;
import dev.lions.unionflow.server.security.AuditTrailService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.WebApplicationException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.Year;
import java.util.UUID;
import org.jboss.logging.Logger;

/**
 * Service de gestion des formations LBC/FT obligatoires.
 *
 * <p>Implémente l'obligation de l'<strong>Instruction BCEAO 001-03-2025</strong> :
 *
 * <ul>
 *   <li>Compliance officer doit être formé annuellement
 *   <li>Dirigeants (président, trésorier, secrétaire) doivent être formés annuellement
 *   <li>Tous les membres exposés (commissaires aux comptes, contrôleurs internes) idem
 * </ul>
 *
 * <p>Le compliance dashboard ({@link
 * dev.lions.unionflow.server.service.compliance.ComplianceDashboardService}) consultera ce
 * service pour calculer le taux de membres formés sur 12 mois glissants.
 *
 * @since 2026-04-25 (P1-NEW-12)
 */
@ApplicationScoped
public class FormationLbcFtService {

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

  @Inject FormationLbcFtRepository formationRepo;
  @Inject ParticipationFormationLbcFtRepository participationRepo;
  @Inject AuditTrailService auditTrail;

  /** Crée une nouvelle session de formation. */
  @Transactional
  public FormationLbcFt creer(FormationLbcFt formation) {
    if (formation.getAnneeReference() == null) {
      formation.setAnneeReference(Year.now().getValue());
    }
    formationRepo.persist(formation);
    auditTrail.logSimple("FormationLbcFt", formation.getId(), "CREATE",
        "Création formation LBC/FT — " + formation.getTitre()
            + " (" + formation.getAnneeReference() + ")");
    return formation;
  }

  /** Inscrit un membre à une formation. */
  @Transactional
  public ParticipationFormationLbcFt inscrire(UUID formationId, UUID membreId) {
    FormationLbcFt formation = formationRepo.findById(formationId);
    if (formation == null) {
      throw new NotFoundException("Formation introuvable : " + formationId);
    }

    ParticipationFormationLbcFt p = ParticipationFormationLbcFt.builder()
        .formation(formation)
        .membreId(membreId)
        .statutParticipation("INSCRIT")
        .build();
    participationRepo.persist(p);
    return p;
  }

  /** Marque un participant comme PRESENT. */
  @Transactional
  public ParticipationFormationLbcFt marquerPresent(UUID participationId) {
    ParticipationFormationLbcFt p = participationRepo.findById(participationId);
    if (p == null) throw new NotFoundException("Participation introuvable : " + participationId);
    p.setStatutParticipation("PRESENT");
    participationRepo.persist(p);
    return p;
  }

  /**
   * Délivre le certificat de formation après réussite (PRESENT + score quiz ≥ 70%).
   *
   * @param scoreQuiz score sur 100 (peut être null si pas de quiz)
   */
  @Transactional
  public ParticipationFormationLbcFt certifier(UUID participationId, BigDecimal scoreQuiz) {
    ParticipationFormationLbcFt p = participationRepo.findById(participationId);
    if (p == null) throw new NotFoundException("Participation introuvable : " + participationId);
    if (!"PRESENT".equals(p.getStatutParticipation())) {
      throw new WebApplicationException(
          "Participant doit être PRESENT avant certification", 400);
    }
    if (scoreQuiz != null && scoreQuiz.compareTo(new BigDecimal("70")) < 0) {
      throw new WebApplicationException(
          "Score quiz < 70 — certification refusée (score=" + scoreQuiz + ")", 400);
    }

    p.setStatutParticipation("CERTIFIE");
    p.setDateCertification(LocalDateTime.now());
    p.setScoreQuiz(scoreQuiz);
    p.setNumeroCertificat("CERT-LBCFT-" + p.getId().toString().substring(0, 8).toUpperCase());
    participationRepo.persist(p);

    auditTrail.logSimple("ParticipationFormationLbcFt", p.getId(), "APPROVE",
        "Certification LBC/FT délivrée — " + p.getNumeroCertificat());
    return p;
  }

  /** Vérifie si un membre est à jour pour l'année courante. */
  public boolean estCertifieAnneeCourante(UUID membreId) {
    return participationRepo.trouverCertificationAnnee(membreId, Year.now().getValue()).isPresent();
  }
}
