package dev.lions.services; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Event; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import dev.lions.models.Contact; import dev.lions.models.ContactForm; import dev.lions.models.ContactStatus; import dev.lions.models.EmailTemplate; import dev.lions.repositories.ContactRepository; import dev.lions.events.ContactSubmissionEvent; import dev.lions.exceptions.BusinessException; import java.time.LocalDateTime; import java.util.Map; /** * Service gérant la logique métier des contacts. * Cette classe assure le traitement des demandes de contact, leur validation, * et la notification des parties concernées. */ @Slf4j @ApplicationScoped public class ContactService { @Inject private ContactRepository contactRepository; @Inject private EmailService emailService; @Inject private Event contactEvent; /** * Traite un nouveau formulaire de contact. * Cette méthode valide les données, enregistre le contact et envoie * les notifications appropriées. * * @param form Formulaire de contact à traiter * @return Contact créé */ @Transactional public Contact processContactForm(@Valid @NotNull ContactForm form) { log.info("Traitement d'une nouvelle demande de contact"); try { validateContactForm(form); Contact contact = createContact(form); sendConfirmationEmails(contact); notifyContactSubmission(contact); log.info("Demande de contact traitée avec succès - ID: {}", contact.getId()); return contact; } catch (BusinessException be) { log.warn("Erreur de validation du formulaire de contact", be); throw be; } catch (Exception e) { log.error("Erreur lors du traitement de la demande de contact", e); throw new BusinessException( "Impossible de traiter la demande de contact", e); } } /** * Valide les données du formulaire de contact. */ private void validateContactForm(ContactForm form) { if (form.getName() == null || form.getName().trim().length() < 2) { throw new BusinessException("Le nom doit contenir au moins 2 caractères"); } if (!isValidEmail(form.getEmail())) { throw new BusinessException("L'adresse email n'est pas valide"); } if (form.getMessage() == null || form.getMessage().trim().length() < 10 || form.getMessage().length() > 1000) { throw new BusinessException( "Le message doit contenir entre 10 et 1000 caractères"); } } /** * Crée une nouvelle entité Contact à partir du formulaire. */ private Contact createContact(ContactForm form) { Contact contact = new Contact( form.getName(), form.getEmail(), form.getSubject(), form.getMessage() ); contact.setStatus(ContactStatus.NEW); contact.setSubmitDate(LocalDateTime.now()); return contactRepository.save(contact); } /** * Envoie les emails de confirmation. */ private void sendConfirmationEmails(Contact contact) { sendCustomerConfirmation(contact); sendAdminNotification(contact); } /** * Envoie l'email de confirmation au client. */ private void sendCustomerConfirmation(Contact contact) { EmailTemplate template = EmailTemplate.builder() .templateName("contact-confirmation") .recipient(contact.getEmail()) .subject("Confirmation de votre message") .parameters(Map.of( "name", contact.getName(), "subject", contact.getSubject(), "message", contact.getMessage(), "contactId", contact.getId().toString() )) .build(); emailService.sendTemplatedEmail(template); } /** * Envoie l'email de notification à l'administrateur. */ private void sendAdminNotification(Contact contact) { EmailTemplate template = EmailTemplate.builder() .templateName("admin-contact-notification") .recipient(emailService.config.getAdminEmailAddress()) .subject("Nouvelle demande de contact") .parameters(Map.of( "name", contact.getName(), "email", contact.getEmail(), "subject", contact.getSubject(), "message", contact.getMessage(), "timestamp", contact.getSubmitDate().toString(), "contactId", contact.getId().toString() )) .build(); emailService.sendTemplatedEmail(template); } /** * Notifie le système de la soumission d'un nouveau contact. */ private void notifyContactSubmission(Contact contact) { contactEvent.fire(new ContactSubmissionEvent(contact)); } /** * Vérifie si une adresse email est valide. */ private boolean isValidEmail(String email) { if (email == null || email.trim().isEmpty()) { return false; } String emailRegex = "^[A-Za-z0-9+_.-]+@(.+)$"; return email.matches(emailRegex); } /** * Met à jour le statut d'un contact. * * @param contactId Identifiant du contact * @param newStatus Nouveau statut * @param note Note optionnelle sur la mise à jour */ @Transactional public void updateContactStatus( @NotNull Long contactId, @NotNull ContactStatus newStatus, String note) { log.info("Mise à jour du statut du contact {} vers {}", contactId, newStatus); try { Contact contact = contactRepository.findById(contactId) .orElseThrow(() -> new BusinessException("Contact non trouvé")); contact.setStatus(newStatus); contact.setProcessDate(LocalDateTime.now()); if (note != null && !note.trim().isEmpty()) { addInternalNote(contact, note); } contactRepository.update(contact); log.info("Statut du contact mis à jour avec succès"); } catch (Exception e) { log.error("Erreur lors de la mise à jour du statut du contact", e); throw new BusinessException( "Impossible de mettre à jour le statut du contact", e); } } /** * Ajoute une note interne à un contact. */ private void addInternalNote(Contact contact, String note) { String currentNotes = contact.getInternalNotes(); String timestamp = LocalDateTime.now().toString(); String newNote = String.format("[%s] %s", timestamp, note); if (currentNotes == null || currentNotes.trim().isEmpty()) { contact.setInternalNotes(newNote); } else { contact.setInternalNotes(currentNotes + "\n" + newNote); } } }