package dev.lions.unionflow.client.view;

import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationSummaryResponse;
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
import dev.lions.unionflow.server.api.dto.document.request.CreateDocumentRequest;
import dev.lions.unionflow.server.api.dto.document.request.CreatePieceJointeRequest;
import dev.lions.unionflow.server.api.dto.membre.request.CreateMembreRequest;
import dev.lions.unionflow.server.api.enums.document.TypeDocument;
import dev.lions.unionflow.client.service.DocumentService;
import dev.lions.unionflow.client.service.MembreService;
import dev.lions.unionflow.client.service.OrganisationService;
import dev.lions.unionflow.client.service.ErrorHandlerService;
import dev.lions.unionflow.client.service.RetryService;
import dev.lions.unionflow.client.service.ValidationService;
import java.util.UUID;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import jakarta.inject.Inject;
import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.logging.Logger;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Named("membreInscriptionBean")
@ViewScoped
public class MembreInscriptionBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(MembreInscriptionBean.class);

    // Constantes de navigation outcomes (WOU/DRY - réutilisables)
    private static final String OUTCOME_MEMBRE_LISTE = "membreListPage";
    private static final String OUTCOME_DASHBOARD = "dashboardPage";

    @Inject
    @RestClient
    MembreService membreService;

    @Inject
    @RestClient
    OrganisationService organisationService;

    @Inject
    ValidationService validationService;

    @Inject
    ErrorHandlerService errorHandler;

    @Inject
    RetryService retryService;

    @Inject
    @RestClient
    DocumentService documentService;

    @Inject
    SouscriptionBean souscriptionBean;

    // Propriétés système
    private String numeroGenere;

    // Informations personnelles
    private String prenom;
    private String nom;
    private String email;
    private String telephone;
    private String telephoneMobile;
    private String adresse;
    private String ville;
    private String codePostal;
    private String pays = "Sénégal";
    private LocalDate dateNaissance;
    private String lieuNaissance;
    private String nationalite = "Sénégalaise";
    private String sexe;
    private String situationMatrimoniale;
    private String profession;
    private String employeur;

    // Informations d'urgence
    private String contactUrgenceNom;
    private String contactUrgenceTelephone;
    private String contactUrgenceLien;

    // Informations bancaires
    private String numeroBanque;
    private String nomBanque;
    private String ribIban;

    // Informations adhésion
    private String typeAdhesion;
    private String numeroParrain;
    private String nomParrain;
    private String motifAdhesion;
    private String organisationId; // ID de l'organisation choisie
    private String organisationNom; // Nom de l'organisation affichée
    private List<OrganisationSummaryResponse> organisationsDisponibles = new ArrayList<>(); // Liste des organisations
    private boolean accepteReglement = false;
    private boolean acceptePrelevement = false;
    private boolean autorisationMarketing = false;

    // Statut de validation
    private String statutValidation = "EN_ATTENTE"; // EN_ATTENTE, VALIDE, REFUSE

    // Informations complémentaires
    private String competencesSpeciales;
    private String centresInteret;
    private String commentaires;

    // Photo et documents
    private String photoPath;
    private List<String> documentsJoints = new ArrayList<>();
    private org.primefaces.model.file.UploadedFile uploadedPhoto;
    private String photoBase64;

    public MembreInscriptionBean() {
        // Initialisation par défaut
    }

    @PostConstruct
    public void init() {
        // Le numéro sera généré automatiquement par le backend lors de la création
        // On utilise un placeholder pour l'affichage (DRY/WOU - le backend gère la
        // génération)
        this.numeroGenere = "À générer automatiquement";

        // Charger les organisations actives (DRY/WOU - utilise OrganisationService)
        try {
            PagedResponse<OrganisationSummaryResponse> response = retryService.executeWithRetrySupplier(
                    () -> organisationService.listerToutes(0, 1000),
                    "chargement des associations");
            organisationsDisponibles = (response != null && response.getData() != null) ? response.getData()
                    : new ArrayList<OrganisationSummaryResponse>();
            LOG.infof("Associations chargées: %d", organisationsDisponibles.size());
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du chargement des organisations");
            errorHandler.handleException(e, "lors du chargement des organisations", null);
            organisationsDisponibles = new ArrayList<>();
        }
    }

    // Actions
    public String inscrire() {
        try {
            // Vérifier d'abord si l'organisation peut accepter de nouveaux membres
            if (!peutAccepterNouveauMembre()) {
                errorHandler.showWarning("Quota atteint", "Cette organisation a atteint son quota maximum de membres.");
                return null;
            }

            // Vérification des champs obligatoires
            if (organisationId == null || organisationId.trim().isEmpty()) {
                errorHandler.showWarning("Organisation manquante", "Vous devez sélectionner une organisation.");
                return null;
            }

            // Convertir l'organisationId String → UUID
            UUID orgUuid = null;
            if (organisationId != null && !organisationId.trim().isEmpty()) {
                try {
                    orgUuid = UUID.fromString(organisationId.trim());
                } catch (IllegalArgumentException e) {
                    errorHandler.showWarning("Erreur", "Identifiant d'organisation invalide.");
                    return null;
                }
            }

            // Construire la requête de création (DTO correct attendu par le backend)
            CreateMembreRequest nouveauMembre = CreateMembreRequest.builder()
                    .prenom(prenom)
                    .nom(nom)
                    .email(email)
                    .telephone(telephoneMobile != null && !telephoneMobile.trim().isEmpty()
                            ? telephoneMobile : telephone)
                    .dateNaissance(dateNaissance)
                    .profession(profession)
                    .statutMatrimonial(situationMatrimoniale)
                    .nationalite(nationalite)
                    .organisationId(orgUuid)
                    .build();

            // Validation des données
            ValidationService.ValidationResult validationResult = validationService.validate(nouveauMembre);
            if (!validationResult.isValid()) {
                List<String> errors = new ArrayList<>();
                if (validationResult.getFirstErrorMessage() != null) {
                    errors.add(validationResult.getFirstErrorMessage());
                }
                errorHandler.handleValidationErrors(errors, "validation du membre");
                return null;
            }

            // Appel du service REST pour créer le membre avec retry
            MembreResponse membreCreee = retryService.executeWithRetrySupplier(
                    () -> membreService.creer(nouveauMembre),
                    "inscription d'un membre");

            // Upload de la photo via DocumentService (non bloquant : le membre est déjà créé)
            if (photoBase64 != null && !photoBase64.trim().isEmpty()) {
                try {
                    // Le contenu base64 est stocké dans cheminStockage ;
                    // taille approximée en octets = nb_chars_base64 * 3/4
                    long tailleApprox = (long) (photoBase64.length() * 0.75);
                    String nomFichierPhoto = "photo-" + membreCreee.getNumeroMembre() + ".jpg";
                    CreateDocumentRequest photoRequest = CreateDocumentRequest.builder()
                            .nomFichier(nomFichierPhoto)
                            .nomOriginal(nomFichierPhoto)
                            .cheminStockage(photoBase64)
                            .typeMime("image/jpeg")
                            .tailleOctets(tailleApprox)
                            .typeDocument(TypeDocument.PHOTO)
                            .description("Photo du membre " + membreCreee.getNomComplet())
                            .build();
                    documentService.creerDocument(photoRequest);
                    LOG.infof("Photo uploadée pour le membre %s", membreCreee.getNumeroMembre());
                } catch (Exception ex) {
                    LOG.warnf(ex, "Impossible d'uploader la photo du membre %s — le membre reste créé",
                            membreCreee.getNumeroMembre());
                }
            }

            // Upload des documents joints via DocumentService (non bloquant)
            if (documentsJoints != null && !documentsJoints.isEmpty()) {
                LOG.infof("Documents joints à uploader: %d fichier(s)", documentsJoints.size());
                for (int i = 0; i < documentsJoints.size(); i++) {
                    String nomDoc = documentsJoints.get(i);
                    try {
                        CreateDocumentRequest docRequest = CreateDocumentRequest.builder()
                                .nomFichier(nomDoc)
                                .nomOriginal(nomDoc)
                                .cheminStockage("membres/" + membreCreee.getNumeroMembre() + "/" + nomDoc)
                                .tailleOctets(0L)
                                .typeDocument(TypeDocument.PIECE_JUSTIFICATIVE)
                                .description("Document joint — " + nomDoc)
                                .build();
                        dev.lions.unionflow.server.api.dto.document.response.DocumentResponse docReponse =
                                documentService.creerDocument(docRequest);
                        // Rattacher le document créé en tant que pièce jointe du membre
                        if (docReponse != null && docReponse.getId() != null) {
                            CreatePieceJointeRequest pjRequest = CreatePieceJointeRequest.builder()
                                    .ordre(i + 1)
                                    .libelle(nomDoc)
                                    .documentId(docReponse.getId())
                                    .typeEntiteRattachee("MEMBRE")
                                    .entiteRattacheeId(membreCreee.getId())
                                    .build();
                            documentService.creerPieceJointe(pjRequest);
                        }
                        LOG.infof("Document '%s' uploadé pour le membre %s", nomDoc, membreCreee.getNumeroMembre());
                    } catch (Exception ex) {
                        LOG.warnf(ex, "Impossible d'uploader le document '%s' pour le membre %s — ignoré",
                                nomDoc, membreCreee.getNumeroMembre());
                    }
                }
            }

            LOG.infof("Membre inscrit avec succès: %s (N° %s)",
                    membreCreee.getNomComplet(), membreCreee.getNumeroMembre());

            // Message de succès
            errorHandler.showSuccess("Inscription réussie",
                    "Le membre " + membreCreee.getNomComplet() + " a été inscrit avec succès (N° "
                            + membreCreee.getNumeroMembre() + ")");

            return OUTCOME_MEMBRE_LISTE + "?faces-redirect=true";

        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de l'inscription");
            errorHandler.handleException(e, "lors de l'inscription d'un membre", null);
            return null;
        }
    }

    // Méthodes de validation en temps réel
    public void validateNom() {
        if (nom != null && !nom.trim().isEmpty()) {
            ValidationService.ValidationResult result = validationService.validateValue(MembreResponse.class, "nom", nom);
            if (!result.isValid()) {
                LOG.debugf("Erreur validation nom: %s", result.getFirstErrorMessage());
            }
        }
    }

    public void validatePrenom() {
        if (prenom != null && !prenom.trim().isEmpty()) {
            ValidationService.ValidationResult result = validationService.validateValue(MembreResponse.class, "prenom",
                    prenom);
            if (!result.isValid()) {
                LOG.debugf("Erreur validation prénom: %s", result.getFirstErrorMessage());
            }
        }
    }

    public void validateEmail() {
        if (email != null && !email.trim().isEmpty()) {
            ValidationService.ValidationResult result = validationService.validateValue(MembreResponse.class, "email",
                    email);
            if (!result.isValid()) {
                LOG.debugf("Erreur validation email: %s", result.getFirstErrorMessage());
            }
        }
    }

    public void validateTelephone() {
        if (telephone != null && !telephone.trim().isEmpty()) {
            ValidationService.ValidationResult result = validationService.validateValue(MembreResponse.class, "telephone",
                    telephone);
            if (!result.isValid()) {
                LOG.debugf("Erreur validation téléphone: %s", result.getFirstErrorMessage());
            }
        }
    }

    public String annuler() {
        return OUTCOME_DASHBOARD + "?faces-redirect=true";
    }

    public void handleFileUpload(org.primefaces.event.FileUploadEvent event) {
        // Logique d'upload de documents
        org.primefaces.model.file.UploadedFile file = event.getFile();
        if (file != null) {
            documentsJoints.add(file.getFileName());
        }
    }

    public void ajouterDocument() {
        // Logique d'ajout de document
    }

    public void supprimerDocument(String document) {
        documentsJoints.remove(document);
    }

    public void rechercherParrain() {
        // Recherche du parrain via le service REST (DRY/WOU - utilise MembreService)
        if (numeroParrain == null || numeroParrain.trim().isEmpty()) {
            nomParrain = null;
            errorHandler.showWarning("Attention", "Veuillez saisir un numéro de membre");
            return;
        }

        try {
            MembreResponse parrain = retryService.executeWithRetrySupplier(
                    () -> membreService.obtenirParNumero(numeroParrain.trim()),
                    "recherche du parrain");

            if (parrain != null) {
                nomParrain = parrain.getNomComplet();
                LOG.infof("Parrain trouvé: %s", nomParrain);
                errorHandler.showSuccess("Succès", "Parrain trouvé: " + nomParrain);
            } else {
                nomParrain = null;
                errorHandler.showWarning("Attention", "Aucun membre trouvé avec ce numéro");
            }
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la recherche du parrain");
            nomParrain = null;
            errorHandler.handleException(e, "lors de la recherche du parrain", null);
        }
    }

    public String enregistrerBrouillon() {
        // Note: L'enregistrement en brouillon pourrait être implémenté via un service
        // de stockage local
        // ou un endpoint backend dédié. Pour l'instant, on affiche juste un message.
        LOG.info("Enregistrement du brouillon d'inscription");
        errorHandler.showInfo("Information", "Fonctionnalité d'enregistrement en brouillon à venir");
        return null; // Rester sur la même page
    }

    // Méthodes pour la progression
    public boolean isEtapePersonnelleComplete() {
        return prenom != null && !prenom.trim().isEmpty() &&
                nom != null && !nom.trim().isEmpty() &&
                dateNaissance != null &&
                sexe != null && !sexe.trim().isEmpty();
    }

    public boolean isEtapeCoordonneeComplete() {
        return adresse != null && !adresse.trim().isEmpty() &&
                ville != null && !ville.trim().isEmpty() &&
                email != null && !email.trim().isEmpty() &&
                telephoneMobile != null && !telephoneMobile.trim().isEmpty();
    }

    public boolean isEtapeAdhesionComplete() {
        return typeAdhesion != null && !typeAdhesion.trim().isEmpty();
    }

    public boolean isEtapeDocumentsComplete() {
        return !documentsJoints.isEmpty() || (photoBase64 != null && !photoBase64.trim().isEmpty());
    }

    public int getProgressionPourcentage() {
        int etapesCompletes = 0;
        if (isEtapePersonnelleComplete())
            etapesCompletes++;
        if (isEtapeCoordonneeComplete())
            etapesCompletes++;
        if (isEtapeAdhesionComplete())
            etapesCompletes++;
        if (isEtapeDocumentsComplete())
            etapesCompletes++;
        return (etapesCompletes * 100) / 4;
    }

    public boolean isFormulaireValide() {
        // Validation minimale : nom, prénom, email et acceptation du règlement
        boolean champsObligatoiresRemplis = nom != null && !nom.trim().isEmpty() &&
                prenom != null && !prenom.trim().isEmpty() &&
                email != null && !email.trim().isEmpty();

        return champsObligatoiresRemplis && accepteReglement;
    }

    // Vérification du quota organisation
    public boolean peutAccepterNouveauMembre() {
        // Si le bean de souscription n'est pas disponible, autoriser l'inscription par
        // défaut
        if (souscriptionBean == null || souscriptionBean.getSouscriptionActive() == null) {
            LOG.info("SouscriptionBean non disponible - autorisation par défaut");
            return true;
        }
        return souscriptionBean.peutAccepterNouveauMembre();
    }

    public String getMessageQuotaOrganisation() {
        if (souscriptionBean != null) {
            return souscriptionBean.getMessageQuota();
        }
        return "Informations de quota non disponibles";
    }

    // Getters et Setters
    public String getNumeroGenere() {
        return numeroGenere;
    }

    public void setNumeroGenere(String numeroGenere) {
        this.numeroGenere = numeroGenere;
    }

    public String getPrenom() {
        return prenom;
    }

    public void setPrenom(String prenom) {
        this.prenom = prenom;
    }

    public String getNom() {
        return nom;
    }

    public void setNom(String nom) {
        this.nom = nom;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getTelephoneMobile() {
        return telephoneMobile;
    }

    public void setTelephoneMobile(String telephoneMobile) {
        this.telephoneMobile = telephoneMobile;
    }

    public String getAdresse() {
        return adresse;
    }

    public void setAdresse(String adresse) {
        this.adresse = adresse;
    }

    public String getVille() {
        return ville;
    }

    public void setVille(String ville) {
        this.ville = ville;
    }

    public String getCodePostal() {
        return codePostal;
    }

    public void setCodePostal(String codePostal) {
        this.codePostal = codePostal;
    }

    public String getPays() {
        return pays;
    }

    public void setPays(String pays) {
        this.pays = pays;
    }

    public LocalDate getDateNaissance() {
        return dateNaissance;
    }

    public void setDateNaissance(LocalDate dateNaissance) {
        this.dateNaissance = dateNaissance;
    }

    public String getLieuNaissance() {
        return lieuNaissance;
    }

    public void setLieuNaissance(String lieuNaissance) {
        this.lieuNaissance = lieuNaissance;
    }

    public String getNationalite() {
        return nationalite;
    }

    public void setNationalite(String nationalite) {
        this.nationalite = nationalite;
    }

    public String getSexe() {
        return sexe;
    }

    public void setSexe(String sexe) {
        this.sexe = sexe;
    }

    public String getSituationMatrimoniale() {
        return situationMatrimoniale;
    }

    public void setSituationMatrimoniale(String situationMatrimoniale) {
        this.situationMatrimoniale = situationMatrimoniale;
    }

    public String getProfession() {
        return profession;
    }

    public void setProfession(String profession) {
        this.profession = profession;
    }

    public String getEmployeur() {
        return employeur;
    }

    public void setEmployeur(String employeur) {
        this.employeur = employeur;
    }

    public String getContactUrgenceNom() {
        return contactUrgenceNom;
    }

    public void setContactUrgenceNom(String contactUrgenceNom) {
        this.contactUrgenceNom = contactUrgenceNom;
    }

    public String getContactUrgenceTelephone() {
        return contactUrgenceTelephone;
    }

    public void setContactUrgenceTelephone(String contactUrgenceTelephone) {
        this.contactUrgenceTelephone = contactUrgenceTelephone;
    }

    public String getContactUrgenceLien() {
        return contactUrgenceLien;
    }

    public void setContactUrgenceLien(String contactUrgenceLien) {
        this.contactUrgenceLien = contactUrgenceLien;
    }

    public String getNumeroBanque() {
        return numeroBanque;
    }

    public void setNumeroBanque(String numeroBanque) {
        this.numeroBanque = numeroBanque;
    }

    public String getNomBanque() {
        return nomBanque;
    }

    public void setNomBanque(String nomBanque) {
        this.nomBanque = nomBanque;
    }

    public String getRibIban() {
        return ribIban;
    }

    public void setRibIban(String ribIban) {
        this.ribIban = ribIban;
    }

    public String getTypeAdhesion() {
        return typeAdhesion;
    }

    public void setTypeAdhesion(String typeAdhesion) {
        this.typeAdhesion = typeAdhesion;
    }

    public String getNumeroParrain() {
        return numeroParrain;
    }

    public void setNumeroParrain(String numeroParrain) {
        this.numeroParrain = numeroParrain;
    }

    public String getNomParrain() {
        return nomParrain;
    }

    public void setNomParrain(String nomParrain) {
        this.nomParrain = nomParrain;
    }

    public String getMotifAdhesion() {
        return motifAdhesion;
    }

    public void setMotifAdhesion(String motifAdhesion) {
        this.motifAdhesion = motifAdhesion;
    }

    public boolean isAccepteReglement() {
        return accepteReglement;
    }

    public void setAccepteReglement(boolean accepteReglement) {
        this.accepteReglement = accepteReglement;
    }

    public boolean isAcceptePrelevement() {
        return acceptePrelevement;
    }

    public void setAcceptePrelevement(boolean acceptePrelevement) {
        this.acceptePrelevement = acceptePrelevement;
    }

    public boolean isAutorisationMarketing() {
        return autorisationMarketing;
    }

    public void setAutorisationMarketing(boolean autorisationMarketing) {
        this.autorisationMarketing = autorisationMarketing;
    }

    public String getCompetencesSpeciales() {
        return competencesSpeciales;
    }

    public void setCompetencesSpeciales(String competencesSpeciales) {
        this.competencesSpeciales = competencesSpeciales;
    }

    public String getCentresInteret() {
        return centresInteret;
    }

    public void setCentresInteret(String centresInteret) {
        this.centresInteret = centresInteret;
    }

    public String getCommentaires() {
        return commentaires;
    }

    public void setCommentaires(String commentaires) {
        this.commentaires = commentaires;
    }

    public String getPhotoPath() {
        return photoPath;
    }

    public void setPhotoPath(String photoPath) {
        this.photoPath = photoPath;
    }

    public List<String> getDocumentsJoints() {
        return documentsJoints;
    }

    public void setDocumentsJoints(List<String> documentsJoints) {
        this.documentsJoints = documentsJoints;
    }

    public org.primefaces.model.file.UploadedFile getUploadedPhoto() {
        return uploadedPhoto;
    }

    public void setUploadedPhoto(org.primefaces.model.file.UploadedFile uploadedPhoto) {
        this.uploadedPhoto = uploadedPhoto;
    }

    public String getPhotoBase64() {
        return photoBase64;
    }

    public void setPhotoBase64(String photoBase64) {
        this.photoBase64 = photoBase64;
    }

    public String getOrganisationId() {
        return organisationId;
    }

    public void setOrganisationId(String organisationId) {
        this.organisationId = organisationId;
    }

    public String getOrganisationNom() {
        return organisationNom;
    }

    public void setOrganisationNom(String organisationNom) {
        this.organisationNom = organisationNom;
    }

    public List<OrganisationSummaryResponse> getOrganisationsDisponibles() {
        return organisationsDisponibles;
    }

    public void setOrganisationsDisponibles(List<OrganisationSummaryResponse> organisationsDisponibles) {
        this.organisationsDisponibles = organisationsDisponibles;
    }

    public String getStatutValidation() {
        return statutValidation;
    }

    public void setStatutValidation(String statutValidation) {
        this.statutValidation = statutValidation;
    }

    // Listes pour les sélections
    public List<String> getSexeOptions() {
        List<String> options = new ArrayList<>();
        options.add("Masculin");
        options.add("Féminin");
        return options;
    }

    public List<String> getSituationMatrimonialeOptions() {
        List<String> options = new ArrayList<>();
        options.add("Célibataire");
        options.add("Marié(e)");
        options.add("Divorcé(e)");
        options.add("Veuf(ve)");
        return options;
    }

    public List<String> getTypeAdhesionOptions() {
        List<String> options = new ArrayList<>();
        options.add("Membre actif");
        options.add("Membre associé");
        options.add("Membre bienfaiteur");
        options.add("Membre honoraire");
        return options;
    }

    public List<String> getContactUrgenceLienOptions() {
        List<String> options = new ArrayList<>();
        options.add("Conjoint(e)");
        options.add("Parent");
        options.add("Enfant");
        options.add("Frère/Sœur");
        options.add("Ami(e)");
        options.add("Autre");
        return options;
    }
}
