package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.notification.request.CreateNotificationRequest;
import dev.lions.unionflow.server.api.dto.versement.request.DeclarerVersementManuelRequest;
import dev.lions.unionflow.server.api.dto.versement.request.InitierDepotEpargneRequest;
import dev.lions.unionflow.server.api.dto.versement.request.InitierVersementWaveRequest;
import dev.lions.unionflow.server.api.dto.versement.response.VersementGatewayResponse;
import dev.lions.unionflow.server.api.dto.versement.response.VersementResponse;
import dev.lions.unionflow.server.api.dto.versement.response.VersementStatutResponse;
import dev.lions.unionflow.server.api.dto.versement.response.VersementSummaryResponse;
import dev.lions.unionflow.server.api.enums.paiement.StatutIntentionPaiement;
import dev.lions.unionflow.server.api.enums.paiement.TypeObjetIntentionPaiement;
import dev.lions.unionflow.server.entity.Cotisation;
import dev.lions.unionflow.server.entity.IntentionPaiement;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Versement;
import dev.lions.unionflow.server.entity.mutuelle.epargne.CompteEpargne;
import dev.lions.unionflow.server.repository.IntentionPaiementRepository;
import dev.lions.unionflow.server.repository.MembreOrganisationRepository;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.TypeReferenceRepository;
import dev.lions.unionflow.server.repository.VersementRepository;
import dev.lions.unionflow.server.repository.mutuelle.epargne.CompteEpargneRepository;
import dev.lions.unionflow.server.service.WaveCheckoutService.WaveCheckoutException;
import dev.lions.unionflow.server.service.WaveCheckoutService.WaveCheckoutSessionResponse;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.NotFoundException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.jboss.logging.Logger;

/**
 * Service métier pour la gestion des versements.
 *
 * <p>Un versement est l'acte de régler une cotisation. Deux flux sont supportés :
 * <ol>
 *   <li><b>Wave</b> : deep link natif, app Wave sur le même téléphone, retour via
 *       {@code unionflow://payment?result=success&ref={intentionId}}</li>
 *   <li><b>Manuel</b> : déclaration espèces/virement/chèque → validation trésorier</li>
 * </ol>
 *
 * @author UnionFlow Team
 * @version 4.0
 * @since 2026-04-13
 */
@ApplicationScoped
public class VersementService {

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

    @Inject VersementRepository versementRepository;
    @Inject MembreRepository membreRepository;
    @Inject KeycloakService keycloakService;
    @Inject TypeReferenceRepository typeReferenceRepository;
    @Inject IntentionPaiementRepository intentionPaiementRepository;
    @Inject WaveCheckoutService waveCheckoutService;
    @Inject CompteEpargneRepository compteEpargneRepository;
    @Inject MembreOrganisationRepository membreOrganisationRepository;
    @Inject NotificationService notificationService;
    @Inject io.quarkus.security.identity.SecurityIdentity securityIdentity;

    // ── Lecture ───────────────────────────────────────────────────────────────

    public VersementResponse trouverParId(UUID id) {
        return versementRepository.findVersementById(id)
            .map(this::convertToResponse)
            .orElseThrow(() -> new NotFoundException("Versement non trouvé : " + id));
    }

    public VersementResponse trouverParNumeroReference(String numeroReference) {
        return versementRepository.findByNumeroReference(numeroReference)
            .map(this::convertToResponse)
            .orElseThrow(() -> new NotFoundException("Versement non trouvé : " + numeroReference));
    }

    public List<VersementSummaryResponse> listerParMembre(UUID membreId) {
        return versementRepository.findByMembreId(membreId).stream()
            .map(this::convertToSummaryResponse)
            .collect(Collectors.toList());
    }

    public BigDecimal calculerMontantTotalConfirmes(LocalDateTime dateDebut, LocalDateTime dateFin) {
        return versementRepository.calculerMontantTotalConfirmes(dateDebut, dateFin);
    }

    /**
     * Historique des versements du membre connecté (auto-détection).
     * Retourne uniquement les versements confirmés/validés.
     */
    public List<VersementSummaryResponse> getMesVersements(int limit) {
        Membre membreConnecte = getMembreConnecte();
        LOG.infof("Historique versements pour %s, limit=%d",
            membreConnecte.getNumeroMembre(), limit);

        List<Versement> versements = versementRepository.getEntityManager()
            .createQuery(
                "SELECT v FROM Versement v "
                    + "WHERE v.membre.id = :membreId "
                    + "AND v.statutPaiement IN ('CONFIRME', 'VALIDE') "
                    + "ORDER BY v.datePaiement DESC",
                Versement.class)
            .setParameter("membreId", membreConnecte.getId())
            .setMaxResults(limit)
            .getResultList();

        return versements.stream()
            .map(this::convertToSummaryResponse)
            .collect(Collectors.toList());
    }

    // ── Validation / Annulation ───────────────────────────────────────────────

    @Transactional
    public VersementResponse validerVersement(UUID id) {
        Versement versement = versementRepository.findVersementById(id)
            .orElseThrow(() -> new NotFoundException("Versement non trouvé : " + id));

        if (versement.isConfirme()) {
            return convertToResponse(versement);
        }

        versement.setStatutPaiement("CONFIRME");
        versement.setDateValidation(LocalDateTime.now());
        versement.setValidateur(keycloakService.getCurrentUserEmail());
        versement.setModifiePar(keycloakService.getCurrentUserEmail());
        versementRepository.persist(versement);

        LOG.infof("Versement validé : %s", id);
        return convertToResponse(versement);
    }

    @Transactional
    public VersementResponse annulerVersement(UUID id) {
        Versement versement = versementRepository.findVersementById(id)
            .orElseThrow(() -> new NotFoundException("Versement non trouvé : " + id));

        if (!versement.peutEtreModifie()) {
            throw new IllegalStateException("Le versement ne peut plus être annulé (statut finalisé)");
        }

        versement.setStatutPaiement("ANNULE");
        versement.setModifiePar(keycloakService.getCurrentUserEmail());
        versementRepository.persist(versement);

        LOG.infof("Versement annulé : %s", id);
        return convertToResponse(versement);
    }

    // ── Flux Wave ─────────────────────────────────────────────────────────────

    /**
     * Initie un versement Wave.
     *
     * <ol>
     *   <li>Crée une {@link IntentionPaiement} (hub Wave interne)</li>
     *   <li>Appelle l'API Wave Checkout → obtient {@code waveLaunchUrl}</li>
     *   <li>Retourne {@link VersementGatewayResponse} avec {@code waveLaunchUrl}
     *       pour que {@code url_launcher} ouvre Wave directement</li>
     * </ol>
     */
    @Transactional
    public VersementGatewayResponse initierVersementWave(InitierVersementWaveRequest request) {
        Membre membreConnecte = getMembreConnecte();
        LOG.infof("Initiation versement Wave — membre %s, cotisation %s",
            membreConnecte.getNumeroMembre(), request.cotisationId());

        Cotisation cotisation = versementRepository.getEntityManager()
            .find(Cotisation.class, request.cotisationId());
        if (cotisation == null) {
            throw new NotFoundException("Cotisation non trouvée : " + request.cotisationId());
        }
        if (!cotisation.getMembre().getId().equals(membreConnecte.getId())) {
            throw new IllegalArgumentException("Cette cotisation n'appartient pas au membre connecté");
        }

        String base = waveCheckoutService.getRedirectBaseUrl().replaceAll("/+$", "");

        // 1. Créer l'intention (détail interne Wave — non exposé dans l'API publique)
        IntentionPaiement intention = IntentionPaiement.builder()
            .utilisateur(membreConnecte)
            .organisation(cotisation.getOrganisation())
            .montantTotal(cotisation.getMontantDu())
            .codeDevise(cotisation.getCodeDevise() != null ? cotisation.getCodeDevise() : "XOF")
            .typeObjet(TypeObjetIntentionPaiement.COTISATION)
            .statut(StatutIntentionPaiement.INITIEE)
            .objetsCibles("[{\"type\":\"COTISATION\",\"id\":\"" + cotisation.getId()
                + "\",\"montant\":" + cotisation.getMontantDu() + "}]")
            .build();
        intentionPaiementRepository.persist(intention);

        // 2. URL success → deep link si mobile, page HTML si web
        boolean isMobile = request.numeroTelephone() != null && !request.numeroTelephone().isBlank();
        String successUrl = base + (isMobile
            ? "/api/wave-redirect/success?ref=" + intention.getId()
            : "/api/wave-redirect/web-success?ref=" + intention.getId());
        String errorUrl = base + "/api/wave-redirect/error?ref=" + intention.getId();
        String amountStr = cotisation.getMontantDu()
            .setScale(0, java.math.RoundingMode.HALF_UP).toString();
        String restrictMobile = toE164(request.numeroTelephone());

        // 3. Appel Wave Checkout API
        WaveCheckoutSessionResponse session;
        try {
            session = waveCheckoutService.createSession(
                amountStr, "XOF", successUrl, errorUrl,
                intention.getId().toString(), restrictMobile);
        } catch (WaveCheckoutException e) {
            LOG.errorf(e, "Wave Checkout API error : %s", e.getMessage());
            intention.setStatut(StatutIntentionPaiement.ECHOUEE);
            intentionPaiementRepository.persist(intention);
            throw new jakarta.ws.rs.BadRequestException("Wave : " + e.getMessage());
        }

        intention.setWaveCheckoutSessionId(session.id);
        intention.setWaveLaunchUrl(session.waveLaunchUrl);
        intention.setStatut(StatutIntentionPaiement.EN_COURS);
        intentionPaiementRepository.persist(intention);

        cotisation.setIntentionPaiement(intention);
        versementRepository.getEntityManager().merge(cotisation);

        // 4. Créer le versement en EN_ATTENTE
        Versement versement = new Versement();
        versement.setNumeroReference("VRS-WAVE-" + intention.getId().toString().substring(0, 8).toUpperCase());
        versement.setMontant(cotisation.getMontantDu());
        versement.setCodeDevise("XOF");
        versement.setMethodePaiement("WAVE");
        versement.setStatutPaiement("EN_ATTENTE");
        versement.setMembre(membreConnecte);
        versement.setReferenceExterne(session.id);
        versement.setNumeroTelephone(request.numeroTelephone());
        versement.setCommentaire("Versement Wave — session " + session.id);
        versement.setCreePar(membreConnecte.getEmail());
        versementRepository.persist(versement);

        LOG.infof("Versement Wave initié : intention=%s, session=%s, waveLaunchUrl=%s",
            intention.getId(), session.id, session.waveLaunchUrl);

        return VersementGatewayResponse.builder()
            .versementId(versement.getId())
            .waveLaunchUrl(session.waveLaunchUrl)
            .waveCheckoutSessionId(session.id)
            .clientReference(intention.getId().toString())
            .montant(cotisation.getMontantDu())
            .statut("EN_ATTENTE")
            .referenceCotisation(cotisation.getNumeroReference())
            .message("Ouvrez Wave pour confirmer le versement, puis vous serez renvoyé dans UnionFlow.")
            .build();
    }

    // ── Flux dépôt épargne ────────────────────────────────────────────────────

    @Transactional
    public VersementGatewayResponse initierDepotEpargneEnLigne(InitierDepotEpargneRequest request) {
        Membre membreConnecte = getMembreConnecte();
        CompteEpargne compte = compteEpargneRepository.findByIdOptional(request.compteId())
            .orElseThrow(() -> new NotFoundException("Compte épargne non trouvé : " + request.compteId()));
        if (!compte.getMembre().getId().equals(membreConnecte.getId())) {
            throw new IllegalArgumentException("Ce compte épargne n'appartient pas au membre connecté");
        }

        String base = waveCheckoutService.getRedirectBaseUrl().replaceAll("/+$", "");
        BigDecimal montant = request.montant().setScale(0, java.math.RoundingMode.HALF_UP);
        String objetsCibles = "[{\"type\":\"DEPOT_EPARGNE\",\"compteId\":\""
            + request.compteId() + "\",\"montant\":" + montant + "}]";

        IntentionPaiement intention = IntentionPaiement.builder()
            .utilisateur(membreConnecte)
            .organisation(compte.getOrganisation())
            .montantTotal(montant)
            .codeDevise("XOF")
            .typeObjet(TypeObjetIntentionPaiement.DEPOT_EPARGNE)
            .statut(StatutIntentionPaiement.INITIEE)
            .objetsCibles(objetsCibles)
            .build();
        intentionPaiementRepository.persist(intention);

        String successUrl = base + "/api/wave-redirect/success?ref=" + intention.getId();
        String errorUrl   = base + "/api/wave-redirect/error?ref="   + intention.getId();

        WaveCheckoutSessionResponse session;
        try {
            session = waveCheckoutService.createSession(
                montant.toString(), "XOF", successUrl, errorUrl,
                intention.getId().toString(), toE164(request.numeroTelephone()));
        } catch (WaveCheckoutException e) {
            LOG.errorf(e, "Wave Checkout (dépôt épargne) : %s", e.getMessage());
            intention.setStatut(StatutIntentionPaiement.ECHOUEE);
            intentionPaiementRepository.persist(intention);
            throw new jakarta.ws.rs.BadRequestException("Wave : " + e.getMessage());
        }

        intention.setWaveCheckoutSessionId(session.id);
        intention.setWaveLaunchUrl(session.waveLaunchUrl);
        intention.setStatut(StatutIntentionPaiement.EN_COURS);
        intentionPaiementRepository.persist(intention);

        LOG.infof("Dépôt épargne Wave initié : intention=%s, compte=%s",
            intention.getId(), request.compteId());

        return VersementGatewayResponse.builder()
            .versementId(intention.getId())
            .waveLaunchUrl(session.waveLaunchUrl)
            .waveCheckoutSessionId(session.id)
            .clientReference(intention.getId().toString())
            .montant(montant)
            .statut("EN_ATTENTE")
            .message("Ouvrez Wave pour confirmer le dépôt, puis vous serez renvoyé dans UnionFlow.")
            .build();
    }

    // ── Polling statut ────────────────────────────────────────────────────────

    /**
     * Vérifie le statut d'une intention Wave.
     * Utilisé par le deep link de retour (mobile) et le polling web.
     */
    @Transactional
    public VersementStatutResponse verifierStatutVersement(UUID intentionId) {
        IntentionPaiement intention = intentionPaiementRepository.findById(intentionId);
        if (intention == null) {
            throw new NotFoundException("Intention non trouvée : " + intentionId);
        }

        if (intention.isCompletee()) {
            return buildStatutResponse(intention, "Versement confirmé !");
        }
        if (StatutIntentionPaiement.EXPIREE.equals(intention.getStatut())
                || StatutIntentionPaiement.ECHOUEE.equals(intention.getStatut())) {
            return buildStatutResponse(intention,
                "Versement " + intention.getStatut().name().toLowerCase());
        }
        if (intention.isExpiree()) {
            intention.setStatut(StatutIntentionPaiement.EXPIREE);
            intentionPaiementRepository.persist(intention);
            return buildStatutResponse(intention, "Session expirée, veuillez recommencer");
        }

        if (intention.getWaveCheckoutSessionId() != null) {
            try {
                WaveCheckoutService.WaveSessionStatusResponse waveStatus =
                    waveCheckoutService.getSession(intention.getWaveCheckoutSessionId());
                if (waveStatus.isSucceeded()) {
                    confirmerVersementWave(intention, waveStatus.transactionId);
                    return buildStatutResponse(intention, "Versement confirmé !");
                } else if (waveStatus.isExpired()) {
                    intention.setStatut(StatutIntentionPaiement.EXPIREE);
                    intentionPaiementRepository.persist(intention);
                    return buildStatutResponse(intention, "Session Wave expirée");
                }
            } catch (WaveCheckoutService.WaveCheckoutException e) {
                LOG.warnf(e, "Impossible de vérifier la session Wave %s — retry au prochain appel",
                    intention.getWaveCheckoutSessionId());
            }
        }

        return buildStatutResponse(intention, "En attente de confirmation Wave...");
    }

    // ── Flux manuel ───────────────────────────────────────────────────────────

    @Transactional
    public VersementResponse declarerVersementManuel(DeclarerVersementManuelRequest request) {
        Membre membreConnecte = getMembreConnecte();
        LOG.infof("Déclaration versement manuel — membre %s, cotisation %s, méthode %s",
            membreConnecte.getNumeroMembre(), request.cotisationId(), request.methodePaiement());

        Cotisation cotisation = versementRepository.getEntityManager()
            .createQuery("SELECT c FROM Cotisation c WHERE c.id = :id", Cotisation.class)
            .setParameter("id", request.cotisationId())
            .getResultList().stream().findFirst()
            .orElseThrow(() -> new NotFoundException("Cotisation non trouvée : " + request.cotisationId()));

        if (!cotisation.getMembre().getId().equals(membreConnecte.getId())) {
            throw new IllegalArgumentException("Cette cotisation n'appartient pas au membre connecté");
        }

        Versement versement = new Versement();
        versement.setNumeroReference("VRS-MAN-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase());
        versement.setMontant(cotisation.getMontantDu());
        versement.setCodeDevise("XOF");
        versement.setMethodePaiement(request.methodePaiement());
        versement.setStatutPaiement("EN_ATTENTE_VALIDATION");
        versement.setMembre(membreConnecte);
        versement.setReferenceExterne(request.reference());
        versement.setCommentaire(request.commentaire());
        versement.setDatePaiement(LocalDateTime.now());
        versement.setCreePar(membreConnecte.getEmail());
        versementRepository.persist(versement);

        // Notifier le trésorier
        membreOrganisationRepository.findFirstByMembreId(membreConnecte.getId())
            .ifPresent(mo -> {
                CreateNotificationRequest notif = CreateNotificationRequest.builder()
                    .typeNotification("VALIDATION_VERSEMENT_REQUIS")
                    .priorite("HAUTE")
                    .sujet("Validation versement manuel requis")
                    .corps("Le membre " + membreConnecte.getNumeroMembre()
                        + " a déclaré un versement manuel de " + versement.getMontant()
                        + " XOF (réf: " + versement.getNumeroReference() + ") à valider.")
                    .organisationId(mo.getOrganisation().getId())
                    .build();
                notificationService.creerNotification(notif);
            });

        LOG.infof("Versement manuel déclaré : %s (EN_ATTENTE_VALIDATION)", versement.getNumeroReference());
        return convertToResponse(versement);
    }

    // ── Réconciliation Wave (appelé par WaveRedirectResource) ─────────────────

    /**
     * Marque l'intention COMPLETEE et met à jour les cotisations cibles.
     * Idempotent : si déjà complétée, retourne sans effet.
     */
    @Transactional
    public void confirmerVersementWave(IntentionPaiement intention, String waveTransactionId) {
        if (intention.isCompletee()) return;

        intention.setStatut(StatutIntentionPaiement.COMPLETEE);
        intention.setDateCompletion(LocalDateTime.now());
        if (waveTransactionId != null) {
            intention.setWaveTransactionId(waveTransactionId);
        }
        intentionPaiementRepository.persist(intention);

        String objetsCibles = intention.getObjetsCibles();
        if (objetsCibles == null || objetsCibles.isBlank()) return;

        try {
            com.fasterxml.jackson.databind.JsonNode arr =
                new com.fasterxml.jackson.databind.ObjectMapper().readTree(objetsCibles);
            if (!arr.isArray()) return;

            for (com.fasterxml.jackson.databind.JsonNode node : arr) {
                if (!"COTISATION".equals(node.path("type").asText())) continue;

                UUID cotisationId = UUID.fromString(node.get("id").asText());
                BigDecimal montant = node.has("montant")
                    ? new BigDecimal(node.get("montant").asText())
                    : intention.getMontantTotal();

                Cotisation cotisation = versementRepository.getEntityManager()
                    .find(Cotisation.class, cotisationId);
                if (cotisation == null) continue;

                cotisation.setMontantPaye(montant);
                cotisation.setStatut("PAYEE");
                cotisation.setDatePaiement(LocalDateTime.now());
                versementRepository.getEntityManager().merge(cotisation);
                LOG.infof("Cotisation %s marquée PAYEE — Wave txn %s",
                    cotisationId, waveTransactionId);
            }
        } catch (Exception e) {
            LOG.errorf(e, "Erreur réconciliation cotisations pour intention %s", intention.getId());
        }
    }

    // ── Méthodes privées ──────────────────────────────────────────────────────

    private Membre getMembreConnecte() {
        String email = securityIdentity.getPrincipal().getName();
        return membreRepository.findByEmail(email)
            .orElseThrow(() -> new NotFoundException(
                "Membre non trouvé pour l'email : " + email));
    }

    private VersementResponse convertToResponse(Versement v) {
        VersementResponse r = new VersementResponse();
        r.setId(v.getId());
        r.setNumeroReference(v.getNumeroReference());
        r.setMontant(v.getMontant());
        r.setCodeDevise(v.getCodeDevise());
        r.setMethodePaiement(v.getMethodePaiement());
        r.setStatutPaiement(v.getStatutPaiement());
        r.setDatePaiement(v.getDatePaiement());
        r.setDateValidation(v.getDateValidation());
        r.setValidateur(v.getValidateur());
        r.setReferenceExterne(v.getReferenceExterne());
        r.setUrlPreuve(v.getUrlPreuve());
        r.setCommentaire(v.getCommentaire());
        r.setNumeroTelephone(v.getNumeroTelephone());
        if (v.getMembre() != null) {
            r.setMembreId(v.getMembre().getId());
        }
        if (v.getTransactionWave() != null) {
            r.setTransactionWaveId(v.getTransactionWave().getId());
        }
        r.setDateCreation(v.getDateCreation());
        r.setDateModification(v.getDateModification());
        r.setActif(v.getActif());
        enrichirLibelles(v, r);
        return r;
    }

    private VersementSummaryResponse convertToSummaryResponse(Versement v) {
        if (v == null) return null;
        return new VersementSummaryResponse(
            v.getId(),
            v.getNumeroReference(),
            v.getMontant(),
            v.getCodeDevise(),
            resolveLibelle("METHODE_PAIEMENT", v.getMethodePaiement()),
            v.getStatutPaiement(),
            resolveLibelle("STATUT_PAIEMENT", v.getStatutPaiement()),
            resolveSeverity("STATUT_PAIEMENT", v.getStatutPaiement()),
            v.getDatePaiement());
    }

    private void enrichirLibelles(Versement v, VersementResponse r) {
        r.setMethodePaiementLibelle(resolveLibelle("METHODE_PAIEMENT", v.getMethodePaiement()));
        r.setStatutPaiementLibelle(resolveLibelle("STATUT_PAIEMENT", v.getStatutPaiement()));
        r.setStatutPaiementSeverity(resolveSeverity("STATUT_PAIEMENT", v.getStatutPaiement()));
    }

    private String resolveLibelle(String domaine, String code) {
        if (code == null) return null;
        return typeReferenceRepository.findByDomaineAndCode(domaine, code)
            .map(dev.lions.unionflow.server.entity.TypeReference::getLibelle)
            .orElse(code);
    }

    private String resolveSeverity(String domaine, String code) {
        if (code == null) return null;
        return typeReferenceRepository.findByDomaineAndCode(domaine, code)
            .map(dev.lions.unionflow.server.entity.TypeReference::getSeverity)
            .orElse("info");
    }

    private VersementStatutResponse buildStatutResponse(IntentionPaiement intention, String message) {
        return VersementStatutResponse.builder()
            .intentionId(intention.getId())
            .statut(intention.getStatut().name())
            .confirme(intention.isCompletee())
            .waveLaunchUrl(intention.getWaveLaunchUrl())
            .waveCheckoutSessionId(intention.getWaveCheckoutSessionId())
            .waveTransactionId(intention.getWaveTransactionId())
            .montant(intention.getMontantTotal())
            .message(message)
            .build();
    }

    /** Format E.164 pour Wave : 771234567 → +221771234567 */
    static String toE164(String numeroTelephone) {
        if (numeroTelephone == null || numeroTelephone.isBlank()) return null;
        String digits = numeroTelephone.replaceAll("\\D", "");
        if (digits.length() == 9 && (digits.startsWith("7") || digits.startsWith("0"))) {
            return "+221" + (digits.startsWith("0") ? digits.substring(1) : digits);
        }
        if (digits.length() >= 9 && digits.startsWith("221")) return "+" + digits;
        return numeroTelephone.startsWith("+") ? numeroTelephone : "+" + digits;
    }
}
