package dev.lions.unionflow.client.view;

import dev.lions.unionflow.client.service.MembreService;
import dev.lions.unionflow.client.service.MembreImportMultipartForm;
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.server.api.dto.organisation.request.*;
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
import dev.lions.unionflow.server.api.dto.organisation.response.*;
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
import lombok.Getter;
import lombok.Setter;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import jakarta.inject.Inject;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.logging.Logger;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.file.UploadedFile;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Named("membreImportBean")
@ViewScoped
@Getter
@Setter
public class MembreImportBean implements Serializable {

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

    @Inject
    @RestClient
    MembreService membreService;

    @Inject
    @RestClient
    OrganisationService organisationService;

    @Inject
    ErrorHandlerService errorHandler;

    @Inject
    RetryService retryService;

    // Fichier à importer
    private UploadedFile fichierImport;

    // Options d'import
    private boolean mettreAJourExistants = false;
    private boolean ignorerErreurs = false;
    private UUID organisationId;
    private String typeMembreDefaut = "";

    // Organisations disponibles
    private List<OrganisationResponse> organisationsDisponibles = new ArrayList<>();

    // Résultat de l'import
    private ResultatImport resultatImport;

    @PostConstruct
    public void init() {
        chargerOrganisations();
    }

    private void chargerOrganisations() {
        organisationsDisponibles = new ArrayList<>();
        try {
            PagedResponse<OrganisationSummaryResponse> response = retryService.executeWithRetrySupplier(
                    () -> organisationService.listerToutes(0, 1000),
                    "chargement des organisations pour import");
            List<OrganisationSummaryResponse> associations = (response != null && response.getData() != null) ? response.getData()
                    : new ArrayList<>();
            for (OrganisationSummaryResponse assoc : associations) {
                OrganisationResponse org = new OrganisationResponse();
                org.setId(assoc.getId());
                org.setNom(assoc.getNom());
                org.setVille(null /* ville not in Summary */);
                organisationsDisponibles.add(org);
            }
            LOG.infof("Organisations chargées: %d organisations", organisationsDisponibles.size());
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du chargement des organisations");
            errorHandler.handleException(e, "lors du chargement des organisations", null);
        }
    }

    /**
     * Gère l'upload du fichier (appelé par PrimeFaces FileUpload)
     */
    public void handleFileUpload(FileUploadEvent event) {
        try {
            fichierImport = event.getFile();

            if (fichierImport == null) {
                errorHandler.showWarning("Attention", "Aucun fichier sélectionné");
                return;
            }

            // Validation de la taille (10 MB max)
            long maxSize = 10 * 1024 * 1024; // 10 MB
            if (fichierImport.getSize() > maxSize) {
                fichierImport = null;
                errorHandler.showWarning("Erreur", "Le fichier est trop volumineux. Taille maximale: 10 MB");
                return;
            }

            // Validation du type de fichier
            String fileName = fichierImport.getFileName().toLowerCase();
            if (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls") && !fileName.endsWith(".csv")) {
                fichierImport = null;
                errorHandler.showWarning("Erreur", "Type de fichier non supporté. Formats acceptés: .xlsx, .xls, .csv");
                return;
            }

            LOG.infof("Fichier sélectionné: %s (%d bytes)", fichierImport.getFileName(), fichierImport.getSize());
            errorHandler.showSuccess("Succès", "Fichier sélectionné: " + fichierImport.getFileName());
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la sélection du fichier");
            errorHandler.handleException(e, "lors de la sélection du fichier", null);
        }
    }

    /**
     * Lance l'import des membres
     */
    public void importerMembres() {
        if (fichierImport == null || fichierImport.getFileName() == null || fichierImport.getFileName().isEmpty()) {
            errorHandler.showWarning("Attention", "Veuillez sélectionner un fichier à importer");
            return;
        }

        // Validation de la taille du fichier
        long maxSize = 10 * 1024 * 1024; // 10 MB
        if (fichierImport.getSize() > maxSize) {
            errorHandler.showWarning("Erreur", "Le fichier est trop volumineux. Taille maximale: 10 MB");
            return;
        }

        // Validation du type de fichier
        String fileName = fichierImport.getFileName().toLowerCase();
        if (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls") && !fileName.endsWith(".csv")) {
            errorHandler.showWarning("Erreur", "Type de fichier non supporté. Formats acceptés: .xlsx, .xls, .csv");
            return;
        }

        try {
            LOG.infof("Début de l'import du fichier: %s (%d bytes)",
                    fichierImport.getFileName(), fichierImport.getSize());

            byte[] fileContent = fichierImport.getContent();
            if (fileContent == null || fileContent.length == 0) {
                errorHandler.showWarning("Erreur", "Le fichier est vide");
                return;
            }

            String fileNameToSend = fichierImport.getFileName();

            // Créer le formulaire multipart
            MembreImportMultipartForm form = new MembreImportMultipartForm();
            form.file = fileContent;
            form.fileName = fileNameToSend;
            form.organisationId = organisationId;
            form.typeMembreDefaut = typeMembreDefaut != null && !typeMembreDefaut.isEmpty() ? typeMembreDefaut
                    : "ACTIF";
            form.mettreAJourExistants = mettreAJourExistants;
            form.ignorerErreurs = ignorerErreurs;

            // Appeler le service REST avec retry
            MembreService.ResultatImportDTO result = retryService.executeWithRetrySupplier(
                    () -> membreService.importerDonnees(form),
                    "import de membres depuis fichier");

            // Convertir le résultat
            resultatImport = new ResultatImport();
            resultatImport.setTotalTraite(result.getTotalLignes() != null ? result.getTotalLignes() : 0);
            resultatImport.setReussis(result.getLignesTraitees() != null ? result.getLignesTraitees() : 0);
            resultatImport.setEchecs(result.getLignesErreur() != null ? result.getLignesErreur() : 0);
            resultatImport.setIgnores(0);

            // Convertir les erreurs
            List<ErreurImport> erreursList = new ArrayList<>();
            if (result.getErreurs() != null && !result.getErreurs().isEmpty()) {
                for (int i = 0; i < result.getErreurs().size(); i++) {
                    ErreurImport erreur = new ErreurImport();
                    erreur.setLigne(i + 1);
                    erreur.setMessage(result.getErreurs().get(i));
                    erreursList.add(erreur);
                }
            }
            resultatImport.setErreurs(erreursList);

            // Message de succès avec détails
            String message = "Import terminé: " + resultatImport.getReussis() + " membre(s) importé(s) avec succès";
            if (resultatImport.getEchecs() > 0) {
                message += ", " + resultatImport.getEchecs() + " erreur(s)";
            }
            if (resultatImport.getTotalTraite() > 0) {
                message += " sur " + resultatImport.getTotalTraite() + " ligne(s) traitée(s)";
            }

            errorHandler.showSuccess("Succès", message);

            LOG.infof("Import terminé: %d réussis, %d échecs sur %d lignes",
                    resultatImport.getReussis(), resultatImport.getEchecs(), resultatImport.getTotalTraite());

            // Réinitialiser le fichier après import réussi
            fichierImport = null;

        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de l'import");

            // Réinitialiser le résultat en cas d'erreur
            resultatImport = null;

            errorHandler.handleException(e, "lors de l'import de membres", null);
        }
    }

    public void telechargerModele() {
        try {
            LOG.info("Téléchargement du modèle d'import");

            byte[] modele = retryService.executeWithRetrySupplier(
                    () -> membreService.telechargerModeleImport(),
                    "téléchargement du modèle d'import");

            if (modele == null || modele.length == 0) {
                errorHandler.showWarning("Erreur", "Le modèle téléchargé est vide");
                return;
            }

            jakarta.faces.context.FacesContext facesContext = jakarta.faces.context.FacesContext.getCurrentInstance();
            HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();

            response.reset();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename=\"modele_import_membres.xlsx\"");
            response.setContentLength(modele.length);

            response.getOutputStream().write(modele);
            response.getOutputStream().flush();
            facesContext.responseComplete();

            LOG.infof("Modèle d'import téléchargé avec succès (%d bytes)", modele.length);
        } catch (IOException e) {
            LOG.errorf(e, "Erreur lors du téléchargement du modèle");
            errorHandler.handleException(e, "lors du téléchargement du modèle d'import", null);
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du téléchargement du modèle");
            errorHandler.handleException(e, "lors du téléchargement du modèle d'import", null);
        }
    }

    public void reinitialiser() {
        fichierImport = null;
        mettreAJourExistants = false;
        ignorerErreurs = false;
        organisationId = null;
        typeMembreDefaut = "";
        resultatImport = null;
    }

    // Classe interne pour le résultat de l'import
    public static class ResultatImport implements Serializable {
        private int totalTraite;
        private int reussis;
        private int echecs;
        private int ignores;
        private List<ErreurImport> erreurs = new ArrayList<>();

        public int getTotalTraite() { return totalTraite; }
        public void setTotalTraite(int totalTraite) { this.totalTraite = totalTraite; }
        public int getReussis() { return reussis; }
        public void setReussis(int reussis) { this.reussis = reussis; }
        public int getEchecs() { return echecs; }
        public void setEchecs(int echecs) { this.echecs = echecs; }
        public int getIgnores() { return ignores; }
        public void setIgnores(int ignores) { this.ignores = ignores; }
        public List<ErreurImport> getErreurs() { return erreurs; }
        public void setErreurs(List<ErreurImport> erreurs) { this.erreurs = erreurs; }
    }

    public static class ErreurImport implements Serializable {
        private int ligne;
        private String message;

        public int getLigne() { return ligne; }
        public void setLigne(int ligne) { this.ligne = ligne; }
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
    }
}
