package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
import dev.lions.unionflow.server.api.enums.membre.StatutMembre;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.MembreOrganisation;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.MembreOrganisationRepository;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import dev.lions.unionflow.server.repository.SouscriptionOrganisationRepository;
import dev.lions.unionflow.server.entity.SouscriptionOrganisation;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jboss.logging.Logger;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import java.awt.Color;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.time.format.DateTimeParseException;
import java.util.*;

/**
 * Service pour l'import et l'export de membres depuis/vers Excel et CSV
 */
@ApplicationScoped
public class MembreImportExportService {

    private static final Logger LOG = Logger.getLogger(MembreImportExportService.class);
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");

    @Inject
    MembreRepository membreRepository;

    @Inject
    OrganisationRepository organisationRepository;

    @Inject
    MembreService membreService;

    @Inject
    SouscriptionOrganisationRepository souscriptionOrganisationRepository;

    @Inject
    MembreOrganisationRepository membreOrganisationRepository;

    /**
     * Importe des membres depuis un fichier Excel ou CSV
     */
    @Transactional
    public ResultatImport importerMembres(
            InputStream fileInputStream,
            String fileName,
            UUID organisationId,
            String typeMembreDefaut,
            boolean mettreAJourExistants,
            boolean ignorerErreurs) {

        LOG.infof("Import de membres depuis le fichier: %s", fileName);

        ResultatImport resultat = new ResultatImport();
        resultat.erreurs = new ArrayList<>();
        resultat.membresImportes = new ArrayList<>();

        try {
            if (fileName == null || fileName.isBlank()) {
                throw new IllegalArgumentException("Le nom du fichier est requis");
            }
            String ext = fileName.toLowerCase();
            if (ext.endsWith(".csv")) {
                return importerDepuisCSV(fileInputStream, organisationId, typeMembreDefaut, mettreAJourExistants,
                        ignorerErreurs);
            }
            if (ext.endsWith(".xlsx") || ext.endsWith(".xls")) {
                return importerDepuisExcel(fileInputStream, organisationId, typeMembreDefaut, mettreAJourExistants,
                        ignorerErreurs);
            }
            throw new IllegalArgumentException(
                    "Format de fichier non supporté. Formats acceptés: .xlsx, .xls, .csv");
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de l'import");
            resultat.erreurs.add(Objects.toString(e.getMessage(), "Erreur inconnue lors de l'import"));
            return resultat;
        }
    }

    /**
     * Importe depuis un fichier Excel
     */
    private ResultatImport importerDepuisExcel(
            InputStream fileInputStream,
            UUID organisationId,
            String typeMembreDefaut,
            boolean mettreAJourExistants,
            boolean ignorerErreurs) throws IOException {

        ResultatImport resultat = new ResultatImport();
        resultat.erreurs = new ArrayList<>();
        resultat.membresImportes = new ArrayList<>();
        int ligneNum = 0;

        try (Workbook workbook = new XSSFWorkbook(fileInputStream)) {
            Sheet sheet = workbook.getSheetAt(0);
            Row headerRow = sheet.getRow(0);

            if (headerRow == null) {
                throw new IllegalArgumentException("Le fichier Excel est vide ou n'a pas d'en-têtes");
            }

            // Mapper les colonnes
            Map<String, Integer> colonnes = mapperColonnes(headerRow);

            // Vérifier les colonnes obligatoires
            if (!colonnes.containsKey("nom") || !colonnes.containsKey("prenom") ||
                    !colonnes.containsKey("email") || !colonnes.containsKey("telephone")) {
                throw new IllegalArgumentException("Colonnes obligatoires manquantes: nom, prenom, email, telephone");
            }

            // Charger organisation et souscription si import pour une organisation (quota)
            Optional<Organisation> orgOpt = organisationId != null
                    ? organisationRepository.findByIdOptional(organisationId)
                    : Optional.empty();
            Optional<SouscriptionOrganisation> souscriptionOpt = organisationId != null
                    ? souscriptionOrganisationRepository.findByOrganisationId(organisationId)
                    : Optional.empty();
            if (organisationId != null && orgOpt.isEmpty()) {
                throw new IllegalArgumentException("Organisation non trouvée: " + organisationId);
            }

            // Lire les données
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                ligneNum = i + 1;
                Row row = sheet.getRow(i);

                if (row == null) {
                    continue;
                }

                try {
                    Membre membre = lireLigneExcel(row, colonnes, organisationId, typeMembreDefaut);

                    // Vérifier si le membre existe déjà
                    Optional<Membre> membreExistant = membreRepository.findByEmail(membre.getEmail());

                    if (membreExistant.isPresent()) {
                        if (mettreAJourExistants) {
                            Membre existant = membreExistant.get();
                            existant.setNom(membre.getNom());
                            existant.setPrenom(membre.getPrenom());
                            existant.setTelephone(membre.getTelephone());
                            existant.setDateNaissance(membre.getDateNaissance());
                            membreRepository.persist(existant);
                            resultat.membresImportes.add(membreService.convertToResponse(existant));
                            resultat.lignesTraitees++;
                        } else {
                            resultat.erreurs.add(String.format("Ligne %d: Membre avec email %s existe déjà", ligneNum,
                                    membre.getEmail()));
                            if (!ignorerErreurs) {
                                throw new IllegalArgumentException("Membre existant trouvé et mise à jour désactivée");
                            }
                        }
                    } else {
                        if (souscriptionOpt.isPresent()) {
                            SouscriptionOrganisation souscription = souscriptionOpt.get();
                            if (souscription.isQuotaDepasse()) {
                                String msg = String.format("Ligne %d: Quota souscription atteint (max %s membres).",
                                        ligneNum, souscription.getQuotaMax());
                                resultat.erreurs.add(msg);
                                if (!ignorerErreurs) throw new IllegalArgumentException(msg);
                                continue;
                            }
                        }
                        membre = membreService.creerMembre(membre);
                        if (orgOpt.isPresent()) {
                            lierMembreOrganisationEtIncrementerQuota(membre, orgOpt.get(), souscriptionOpt, typeMembreDefaut);
                        }
                        resultat.membresImportes.add(membreService.convertToResponse(membre));
                        resultat.lignesTraitees++;
                    }
                } catch (Exception e) {
                    String erreur = String.format("Ligne %d: %s", ligneNum, e.getMessage());
                    resultat.erreurs.add(erreur);
                    resultat.lignesErreur++;

                    if (!ignorerErreurs) {
                        throw new RuntimeException(erreur, e);
                    }
                }
            }

            resultat.totalLignes = sheet.getLastRowNum();
        }

        LOG.infof("Import terminé: %d lignes traitées, %d erreurs", resultat.lignesTraitees, resultat.lignesErreur);
        return resultat;
    }

    /**
     * Importe depuis un fichier CSV
     */
    private ResultatImport importerDepuisCSV(
            InputStream fileInputStream,
            UUID organisationId,
            String typeMembreDefaut,
            boolean mettreAJourExistants,
            boolean ignorerErreurs) throws IOException {

        ResultatImport resultat = new ResultatImport();
        resultat.erreurs = new ArrayList<>();
        resultat.membresImportes = new ArrayList<>();

        Optional<Organisation> orgOpt = organisationId != null
                ? organisationRepository.findByIdOptional(organisationId)
                : Optional.empty();
        Optional<SouscriptionOrganisation> souscriptionOpt = organisationId != null
                ? souscriptionOrganisationRepository.findByOrganisationId(organisationId)
                : Optional.empty();
        if (organisationId != null && orgOpt.isEmpty()) {
            throw new IllegalArgumentException("Organisation non trouvée: " + organisationId);
        }

        try (InputStreamReader reader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8)) {
            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true).build()
                    .parse(reader);

            int ligneNum = 0;
            for (CSVRecord record : records) {
                ligneNum++;

                try {
                    Membre membre = lireLigneCSV(record, organisationId, typeMembreDefaut);

                    // Vérifier si le membre existe déjà
                    Optional<Membre> membreExistant = membreRepository.findByEmail(membre.getEmail());

                    if (membreExistant.isPresent()) {
                        if (mettreAJourExistants) {
                            Membre existant = membreExistant.get();
                            existant.setNom(membre.getNom());
                            existant.setPrenom(membre.getPrenom());
                            existant.setTelephone(membre.getTelephone());
                            existant.setDateNaissance(membre.getDateNaissance());
                            membreRepository.persist(existant);
                            resultat.membresImportes.add(membreService.convertToResponse(existant));
                            resultat.lignesTraitees++;
                        } else {
                            resultat.erreurs.add(String.format("Ligne %d: Membre avec email %s existe déjà", ligneNum,
                                    membre.getEmail()));
                            if (!ignorerErreurs) {
                                throw new IllegalArgumentException("Membre existant trouvé et mise à jour désactivée");
                            }
                        }
                    } else {
                        if (souscriptionOpt.isPresent()) {
                            SouscriptionOrganisation souscription = souscriptionOpt.get();
                            if (souscription.isQuotaDepasse()) {
                                String msg = String.format("Ligne %d: Quota souscription atteint (max %s membres).",
                                        ligneNum, souscription.getQuotaMax());
                                resultat.erreurs.add(msg);
                                if (!ignorerErreurs) throw new IllegalArgumentException(msg);
                                continue;
                            }
                        }
                        membre = membreService.creerMembre(membre);
                        if (orgOpt.isPresent()) {
                            lierMembreOrganisationEtIncrementerQuota(membre, orgOpt.get(), souscriptionOpt, typeMembreDefaut);
                        }
                        resultat.membresImportes.add(membreService.convertToResponse(membre));
                        resultat.lignesTraitees++;
                    }
                } catch (Exception e) {
                    String erreur = String.format("Ligne %d: %s", ligneNum, e.getMessage());
                    resultat.erreurs.add(erreur);
                    resultat.lignesErreur++;

                    if (!ignorerErreurs) {
                        throw new RuntimeException(erreur, e);
                    }
                }
            }

            resultat.totalLignes = ligneNum;
        }

        LOG.infof("Import CSV terminé: %d lignes traitées, %d erreurs", resultat.lignesTraitees, resultat.lignesErreur);
        return resultat;
    }

    /**
     * Crée le lien MembreOrganisation (adhésion) et incrémente le quota souscription.
     */
    private void lierMembreOrganisationEtIncrementerQuota(
            Membre membre,
            Organisation organisation,
            Optional<SouscriptionOrganisation> souscriptionOpt,
            String typeMembreDefaut) {
        StatutMembre statut = ("ACTIF".equalsIgnoreCase(typeMembreDefaut))
                ? StatutMembre.ACTIF
                : StatutMembre.EN_ATTENTE_VALIDATION;
        MembreOrganisation mo = MembreOrganisation.builder()
                .membre(membre)
                .organisation(organisation)
                .statutMembre(statut)
                .dateAdhesion(LocalDate.now())
                .build();
        membreOrganisationRepository.persist(mo);
        souscriptionOpt.ifPresent(souscription -> {
            souscription.incrementerQuota();
            souscriptionOrganisationRepository.persist(souscription);
        });
    }

    /**
     * Lit une ligne Excel et crée un membre
     */
    private Membre lireLigneExcel(Row row, Map<String, Integer> colonnes, UUID organisationId,
            String typeMembreDefaut) {
        Membre membre = new Membre();

        // Colonnes obligatoires
        String nom = getCellValueAsString(row, colonnes.get("nom"));
        String prenom = getCellValueAsString(row, colonnes.get("prenom"));
        String email = getCellValueAsString(row, colonnes.get("email"));
        String telephone = getCellValueAsString(row, colonnes.get("telephone"));

        if (nom == null || nom.trim().isEmpty()) {
            throw new IllegalArgumentException("Le nom est obligatoire");
        }
        if (prenom == null || prenom.trim().isEmpty()) {
            throw new IllegalArgumentException("Le prénom est obligatoire");
        }
        if (email == null || email.trim().isEmpty()) {
            throw new IllegalArgumentException("L'email est obligatoire");
        }
        if (telephone == null || telephone.trim().isEmpty()) {
            throw new IllegalArgumentException("Le téléphone est obligatoire");
        }

        membre.setNom(nom.trim());
        membre.setPrenom(prenom.trim());
        membre.setEmail(email.trim().toLowerCase());
        membre.setTelephone(telephone.trim());

        // Colonnes optionnelles
        if (colonnes.containsKey("date_naissance")) {
            LocalDate dateNaissance = getCellValueAsDate(row, colonnes.get("date_naissance"));
            if (dateNaissance != null) {
                membre.setDateNaissance(dateNaissance);
            }
        }
        if (membre.getDateNaissance() == null) {
            membre.setDateNaissance(LocalDate.now().minusYears(18));
        }

        if (colonnes.containsKey("date_adhesion")) {
            LocalDate dateAdhesion = getCellValueAsDate(row, colonnes.get("date_adhesion"));
            if (dateAdhesion != null) {
            }
        }

        // Organisation
        if (organisationId != null) {
            Optional<Organisation> org = organisationRepository.findByIdOptional(organisationId);
            if (org.isPresent()) {
            }
        }

        // Statut par défaut
        membre.setActif(typeMembreDefaut == null || typeMembreDefaut.isEmpty() || "ACTIF".equals(typeMembreDefaut));

        return membre;
    }

    /**
     * Lit une ligne CSV et crée un membre
     */
    private Membre lireLigneCSV(CSVRecord record, UUID organisationId, String typeMembreDefaut) {
        Membre membre = new Membre();

        // Colonnes obligatoires
        String nom = record.get("nom");
        String prenom = record.get("prenom");
        String email = record.get("email");
        String telephone = record.get("telephone");

        if (nom == null || nom.trim().isEmpty()) {
            throw new IllegalArgumentException("Le nom est obligatoire");
        }
        if (prenom == null || prenom.trim().isEmpty()) {
            throw new IllegalArgumentException("Le prénom est obligatoire");
        }
        if (email == null || email.trim().isEmpty()) {
            throw new IllegalArgumentException("L'email est obligatoire");
        }
        if (telephone == null || telephone.trim().isEmpty()) {
            throw new IllegalArgumentException("Le téléphone est obligatoire");
        }

        membre.setNom(nom.trim());
        membre.setPrenom(prenom.trim());
        membre.setEmail(email.trim().toLowerCase());
        membre.setTelephone(telephone.trim());

        // Colonnes optionnelles
        try {
            String dateNaissanceStr = record.get("date_naissance");
            if (dateNaissanceStr != null && !dateNaissanceStr.trim().isEmpty()) {
                membre.setDateNaissance(parseDate(dateNaissanceStr));
            }
        } catch (Exception e) {
            // Ignorer si la date est invalide
        }
        if (membre.getDateNaissance() == null) {
            membre.setDateNaissance(LocalDate.now().minusYears(18));
        }

        try {
            String dateAdhesionStr = record.get("date_adhesion");
            if (dateAdhesionStr != null && !dateAdhesionStr.trim().isEmpty()) {
            }
        } catch (Exception e) {
            // Ignorer si la date est invalide
        }

        // Organisation
        if (organisationId != null) {
            Optional<Organisation> org = organisationRepository.findByIdOptional(organisationId);
            if (org.isPresent()) {
            }
        }

        // Statut par défaut
        membre.setActif(typeMembreDefaut == null || typeMembreDefaut.isEmpty() || "ACTIF".equals(typeMembreDefaut));

        return membre;
    }

    /**
     * Mappe les colonnes Excel
     */
    private Map<String, Integer> mapperColonnes(Row headerRow) {
        Map<String, Integer> colonnes = new HashMap<>();
        for (Cell cell : headerRow) {
            String headerName = getCellValueAsString(headerRow, cell.getColumnIndex()).toLowerCase()
                    .replace(" ", "_")
                    .replace("é", "e")
                    .replace("è", "e")
                    .replace("ê", "e");
            colonnes.put(headerName, cell.getColumnIndex());
        }
        return colonnes;
    }

    /**
     * Obtient la valeur d'une cellule comme String
     */
    private String getCellValueAsString(Row row, Integer columnIndex) {
        if (columnIndex == null || row == null) {
            return null;
        }
        Cell cell = row.getCell(columnIndex);
        if (cell == null) {
            return null;
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return String.valueOf((long) cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return null;
        }
    }

    /**
     * Obtient la valeur d'une cellule comme Date
     */
    private LocalDate getCellValueAsDate(Row row, Integer columnIndex) {
        if (columnIndex == null || row == null) {
            return null;
        }
        Cell cell = row.getCell(columnIndex);
        if (cell == null) {
            return null;
        }

        try {
            if (cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) {
                return cell.getDateCellValue().toInstant()
                        .atZone(java.time.ZoneId.systemDefault())
                        .toLocalDate();
            } else if (cell.getCellType() == CellType.STRING) {
                return parseDate(cell.getStringCellValue());
            }
        } catch (Exception e) {
            LOG.warnf("Erreur lors de la lecture de la date: %s", e.getMessage());
        }
        return null;
    }

    /**
     * Parse une date depuis une String
     */
    private LocalDate parseDate(String dateStr) {
        if (dateStr == null || dateStr.trim().isEmpty()) {
            return null;
        }

        dateStr = dateStr.trim();

        // Essayer différents formats
        String[] formats = {
                "dd/MM/yyyy",
                "yyyy-MM-dd",
                "dd-MM-yyyy",
                "dd.MM.yyyy"
        };

        for (String format : formats) {
            try {
                return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(format));
            } catch (DateTimeParseException e) {
                // Continuer avec le format suivant
            }
        }

        throw new IllegalArgumentException("Format de date non reconnu: " + dateStr);
    }

    /**
     * Exporte des membres vers Excel
     */
    public byte[] exporterVersExcel(List<MembreResponse> membres, List<String> colonnesExport, boolean inclureHeaders,
            boolean formaterDates, boolean inclureStatistiques, String motDePasse) throws IOException {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("Membres");

            int rowNum = 0;

            // En-têtes
            if (inclureHeaders) {
                Row headerRow = sheet.createRow(rowNum++);
                int colNum = 0;

                if (colonnesExport.contains("PERSO") || colonnesExport.isEmpty()) {
                    headerRow.createCell(colNum++).setCellValue("Nom");
                    headerRow.createCell(colNum++).setCellValue("Prénom");
                    headerRow.createCell(colNum++).setCellValue("Date de naissance");
                }
                if (colonnesExport.contains("CONTACT") || colonnesExport.isEmpty()) {
                    headerRow.createCell(colNum++).setCellValue("Email");
                    headerRow.createCell(colNum++).setCellValue("Téléphone");
                }
                if (colonnesExport.contains("ADHESION") || colonnesExport.isEmpty()) {
                    headerRow.createCell(colNum++).setCellValue("Date adhésion");
                    headerRow.createCell(colNum++).setCellValue("Statut");
                }
                if (colonnesExport.contains("ORGANISATION") || colonnesExport.isEmpty()) {
                    headerRow.createCell(colNum++).setCellValue("Organisation");
                }
            }

            // Données
            for (MembreResponse membre : membres) {
                Row row = sheet.createRow(rowNum++);
                int colNum = 0;

                if (colonnesExport.contains("PERSO") || colonnesExport.isEmpty()) {
                    row.createCell(colNum++).setCellValue(membre.getNom() != null ? membre.getNom() : "");
                    row.createCell(colNum++).setCellValue(membre.getPrenom() != null ? membre.getPrenom() : "");
                    if (membre.getDateNaissance() != null) {
                        Cell dateCell = row.createCell(colNum++);
                        if (formaterDates) {
                            dateCell.setCellValue(membre.getDateNaissance().format(DATE_FORMATTER));
                        } else {
                            dateCell.setCellValue(membre.getDateNaissance().toString());
                        }
                    } else {
                        row.createCell(colNum++).setCellValue("");
                    }
                }
                if (colonnesExport.contains("CONTACT") || colonnesExport.isEmpty()) {
                    row.createCell(colNum++).setCellValue(membre.getEmail() != null ? membre.getEmail() : "");
                    row.createCell(colNum++).setCellValue(membre.getTelephone() != null ? membre.getTelephone() : "");
                }
                if (colonnesExport.contains("ADHESION") || colonnesExport.isEmpty()) {
                    row.createCell(colNum++).setCellValue(""); // date d'adhésion dans MembreOrganisation
                    row.createCell(colNum++)
                            .setCellValue(membre.getStatutCompte() != null ? membre.getStatutCompte() : "");
                }
                if (colonnesExport.contains("ORGANISATION") || colonnesExport.isEmpty()) {
                    row.createCell(colNum++)
                            .setCellValue(membre.getOrganisationNom() != null ? membre.getOrganisationNom() : "");
                }
            }

            // Auto-size columns
            for (int i = 0; i < 10; i++) {
                sheet.autoSizeColumn(i);
            }

            // Ajouter un onglet statistiques si demandé
            if (inclureStatistiques && !membres.isEmpty()) {
                Sheet statsSheet = workbook.createSheet("Statistiques");
                creerOngletStatistiques(statsSheet, membres);
            }

            // Écrire dans un ByteArrayOutputStream
            try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                workbook.write(outputStream);
                byte[] excelData = outputStream.toByteArray();

                // Chiffrer le fichier si un mot de passe est fourni
                if (motDePasse != null && !motDePasse.trim().isEmpty()) {
                    return chiffrerExcel(excelData, motDePasse);
                }

                return excelData;
            }
        }
    }

    /**
     * Crée un onglet statistiques dans le classeur Excel
     */
    private void creerOngletStatistiques(Sheet sheet, List<MembreResponse> membres) {
        int rowNum = 0;

        // Titre
        Row titleRow = sheet.createRow(rowNum++);
        Cell titleCell = titleRow.createCell(0);
        titleCell.setCellValue("Statistiques des Membres");
        CellStyle titleStyle = sheet.getWorkbook().createCellStyle();
        Font titleFont = sheet.getWorkbook().createFont();
        titleFont.setBold(true);
        titleFont.setFontHeightInPoints((short) 14);
        titleStyle.setFont(titleFont);
        titleCell.setCellStyle(titleStyle);

        rowNum++; // Ligne vide

        // Statistiques générales
        Row headerRow = sheet.createRow(rowNum++);
        headerRow.createCell(0).setCellValue("Indicateur");
        headerRow.createCell(1).setCellValue("Valeur");

        // Style pour les en-têtes
        CellStyle headerStyle = sheet.getWorkbook().createCellStyle();
        Font headerFont = sheet.getWorkbook().createFont();
        headerFont.setBold(true);
        headerStyle.setFont(headerFont);
        headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        headerRow.getCell(0).setCellStyle(headerStyle);
        headerRow.getCell(1).setCellStyle(headerStyle);

        // Calcul des statistiques
        long totalMembres = membres.size();
        long membresActifs = membres.stream()
                .filter(m -> dev.lions.unionflow.server.api.enums.membre.StatutMembre.ACTIF.name()
                        .equals(m.getStatutCompte()))
                .count();
        long membresInactifs = membres.stream()
                .filter(m -> dev.lions.unionflow.server.api.enums.membre.StatutMembre.INACTIF
                        .name().equals(m.getStatutCompte()))
                .count();
        long membresSuspendus = membres.stream()
                .filter(m -> dev.lions.unionflow.server.api.enums.membre.StatutMembre.SUSPENDU
                        .name().equals(m.getStatutCompte()))
                .count();

        // Organisations distinctes
        long organisationsDistinctes = membres.stream()
                .filter(m -> m.getOrganisationNom() != null)
                .map(MembreResponse::getOrganisationNom)
                .distinct()
                .count();

        // Statistiques par type (si disponible dans le DTO)
        // Note: Le type de membre peut ne pas être disponible dans MembreResponse
        // Pour l'instant, on utilise le statut comme indicateur
        long typeActif = membresActifs;
        long typeAssocie = 0;
        long typeBienfaiteur = 0;
        long typeHonoraire = 0;

        // Ajout des statistiques
        int currentRow = rowNum;
        sheet.createRow(currentRow++).createCell(0).setCellValue("Total Membres");
        sheet.getRow(currentRow - 1).createCell(1).setCellValue(totalMembres);

        sheet.createRow(currentRow++).createCell(0).setCellValue("Membres Actifs");
        sheet.getRow(currentRow - 1).createCell(1).setCellValue(membresActifs);

        sheet.createRow(currentRow++).createCell(0).setCellValue("Membres Inactifs");
        sheet.getRow(currentRow - 1).createCell(1).setCellValue(membresInactifs);

        sheet.createRow(currentRow++).createCell(0).setCellValue("Membres Suspendus");
        sheet.getRow(currentRow - 1).createCell(1).setCellValue(membresSuspendus);

        sheet.createRow(currentRow++).createCell(0).setCellValue("Organisations Distinctes");
        sheet.getRow(currentRow - 1).createCell(1).setCellValue(organisationsDistinctes);

        currentRow++; // Ligne vide

        // Section par type
        sheet.createRow(currentRow++).createCell(0).setCellValue("Répartition par Type");
        CellStyle sectionStyle = sheet.getWorkbook().createCellStyle();
        Font sectionFont = sheet.getWorkbook().createFont();
        sectionFont.setBold(true);
        sectionStyle.setFont(sectionFont);
        sheet.getRow(currentRow - 1).getCell(0).setCellStyle(sectionStyle);

        sheet.createRow(currentRow++).createCell(0).setCellValue("Type Actif");
        sheet.getRow(currentRow - 1).createCell(1).setCellValue(typeActif);

        sheet.createRow(currentRow++).createCell(0).setCellValue("Type Associé");
        sheet.getRow(currentRow - 1).createCell(1).setCellValue(typeAssocie);

        sheet.createRow(currentRow++).createCell(0).setCellValue("Type Bienfaiteur");
        sheet.getRow(currentRow - 1).createCell(1).setCellValue(typeBienfaiteur);

        sheet.createRow(currentRow++).createCell(0).setCellValue("Type Honoraire");
        sheet.getRow(currentRow - 1).createCell(1).setCellValue(typeHonoraire);

        // Auto-size columns
        sheet.autoSizeColumn(0);
        sheet.autoSizeColumn(1);
    }

    /**
     * Protège un fichier Excel avec un mot de passe
     * Utilise Apache POI pour protéger les feuilles et la structure du workbook
     * Note: Ceci protège contre la modification, pas un chiffrement complet du
     * fichier
     */
    private byte[] chiffrerExcel(byte[] excelData, String motDePasse) throws IOException {
        try {
            // Pour XLSX, on protège les feuilles et la structure du workbook
            // Note: POI 5.2.5 ne supporte pas le chiffrement complet XLSX (nécessite des
            // bibliothèques externes)
            // On utilise la protection par mot de passe qui empêche la modification sans le
            // mot de passe

            try (java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(excelData);
                    XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

                // Protéger toutes les feuilles avec un mot de passe (empêche la modification
                // des cellules)
                for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                    Sheet sheet = workbook.getSheetAt(i);
                    sheet.protectSheet(motDePasse);
                }

                // Protéger la structure du workbook (empêche l'ajout/suppression de feuilles)
                org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookProtection protection = workbook
                        .getCTWorkbook().getWorkbookProtection();
                if (protection == null) {
                    protection = workbook.getCTWorkbook().addNewWorkbookProtection();
                }
                protection.setLockStructure(true);
                // Le mot de passe doit être haché selon le format Excel
                // Pour simplifier, on utilise le hash MD5 du mot de passe
                java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
                byte[] passwordHash = md.digest(motDePasse.getBytes(java.nio.charset.StandardCharsets.UTF_16LE));
                protection.setWorkbookPassword(passwordHash);

                workbook.write(outputStream);
                return outputStream.toByteArray();
            }
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la protection du fichier Excel");
            // En cas d'erreur, retourner le fichier non protégé avec un avertissement
            LOG.warnf("Le fichier sera exporté sans protection en raison d'une erreur");
            return excelData;
        }
    }

    /**
     * Exporte des membres vers CSV
     */
    public byte[] exporterVersCSV(List<MembreResponse> membres, List<String> colonnesExport, boolean inclureHeaders,
            boolean formaterDates) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                CSVPrinter printer = new CSVPrinter(
                        new java.io.OutputStreamWriter(outputStream, StandardCharsets.UTF_8),
                        CSVFormat.DEFAULT)) {

            // En-têtes
            if (inclureHeaders) {
                List<String> headers = new ArrayList<>();
                if (colonnesExport.contains("PERSO") || colonnesExport.isEmpty()) {
                    headers.add("Nom");
                    headers.add("Prénom");
                    headers.add("Date de naissance");
                }
                if (colonnesExport.contains("CONTACT") || colonnesExport.isEmpty()) {
                    headers.add("Email");
                    headers.add("Téléphone");
                }
                if (colonnesExport.contains("ADHESION") || colonnesExport.isEmpty()) {
                    headers.add("Date adhésion");
                    headers.add("Statut");
                }
                if (colonnesExport.contains("ORGANISATION") || colonnesExport.isEmpty()) {
                    headers.add("Organisation");
                }
                printer.printRecord(headers);
            }

            // Données
            for (MembreResponse membre : membres) {
                List<String> values = new ArrayList<>();

                if (colonnesExport.contains("PERSO") || colonnesExport.isEmpty()) {
                    values.add(membre.getNom() != null ? membre.getNom() : "");
                    values.add(membre.getPrenom() != null ? membre.getPrenom() : "");
                    if (membre.getDateNaissance() != null) {
                        values.add(formaterDates ? membre.getDateNaissance().format(DATE_FORMATTER)
                                : membre.getDateNaissance().toString());
                    } else {
                        values.add("");
                    }
                }
                if (colonnesExport.contains("CONTACT") || colonnesExport.isEmpty()) {
                    values.add(membre.getEmail() != null ? membre.getEmail() : "");
                    values.add(membre.getTelephone() != null ? membre.getTelephone() : "");
                }
                if (colonnesExport.contains("ADHESION") || colonnesExport.isEmpty()) {
                    values.add(""); // date d'adhésion dans MembreOrganisation
                    values.add(membre.getStatutCompte() != null ? membre.getStatutCompte() : "");
                }
                if (colonnesExport.contains("ORGANISATION") || colonnesExport.isEmpty()) {
                    values.add(Objects.toString(membre.getOrganisationNom(), ""));
                }

                printer.printRecord(values);
            }

            printer.flush();
            return outputStream.toByteArray();
        }
    }

    /**
     * Exporte des membres vers PDF
     */
    public byte[] exporterVersPDF(List<MembreResponse> membres, List<String> colonnesExport, boolean inclureHeaders,
            boolean formaterDates, boolean inclureStatistiques) throws IOException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            Document document = new Document(PageSize.A4.rotate()); // Landscape pour plus de colonnes
            PdfWriter.getInstance(document, outputStream);
            document.open();

            // Titre
            com.lowagie.text.Font titleFont = new com.lowagie.text.Font(com.lowagie.text.Font.HELVETICA, 18, com.lowagie.text.Font.BOLD, Color.DARK_GRAY);
            Paragraph title = new Paragraph("Export des Membres", titleFont);
            title.setAlignment(Element.ALIGN_CENTER);
            title.setSpacingAfter(20);
            document.add(title);

            // Métadonnées
            com.lowagie.text.Font metaFont = new com.lowagie.text.Font(com.lowagie.text.Font.HELVETICA, 10, com.lowagie.text.Font.NORMAL, Color.GRAY);
            Paragraph meta = new Paragraph("Généré le " + LocalDate.now().format(DATE_FORMATTER) + " | Total: " + membres.size() + " membres", metaFont);
            meta.setAlignment(Element.ALIGN_CENTER);
            meta.setSpacingAfter(15);
            document.add(meta);

            // Déterminer les colonnes à afficher
            boolean inclurePerso = colonnesExport.contains("PERSO") || colonnesExport.isEmpty();
            boolean inclureContact = colonnesExport.contains("CONTACT") || colonnesExport.isEmpty();
            boolean inclureAdhesion = colonnesExport.contains("ADHESION") || colonnesExport.isEmpty();
            boolean inclureOrg = colonnesExport.contains("ORGANISATION") || colonnesExport.isEmpty();

            // Calculer nombre de colonnes
            int colCount = 0;
            if (inclurePerso) colCount += 3; // Nom, Prénom, Date naissance
            if (inclureContact) colCount += 2; // Email, Téléphone
            if (inclureAdhesion) colCount += 2; // Date adhésion, Statut
            if (inclureOrg) colCount += 1; // Organisation

            // Créer le tableau
            PdfPTable table = new PdfPTable(colCount);
            table.setWidthPercentage(100);
            table.setSpacingBefore(10);

            // Style des en-têtes
            com.lowagie.text.Font headerFont = new com.lowagie.text.Font(com.lowagie.text.Font.HELVETICA, 10, com.lowagie.text.Font.BOLD, Color.WHITE);
            Color headerBgColor = new Color(52, 73, 94); // Bleu foncé

            // En-têtes
            if (inclureHeaders) {
                if (inclurePerso) {
                    table.addCell(createHeaderCell("Nom", headerFont, headerBgColor));
                    table.addCell(createHeaderCell("Prénom", headerFont, headerBgColor));
                    table.addCell(createHeaderCell("Date Naissance", headerFont, headerBgColor));
                }
                if (inclureContact) {
                    table.addCell(createHeaderCell("Email", headerFont, headerBgColor));
                    table.addCell(createHeaderCell("Téléphone", headerFont, headerBgColor));
                }
                if (inclureAdhesion) {
                    table.addCell(createHeaderCell("Date Adhésion", headerFont, headerBgColor));
                    table.addCell(createHeaderCell("Statut", headerFont, headerBgColor));
                }
                if (inclureOrg) {
                    table.addCell(createHeaderCell("Organisation", headerFont, headerBgColor));
                }
            }

            // Style des cellules de données
            com.lowagie.text.Font dataFont = new com.lowagie.text.Font(com.lowagie.text.Font.HELVETICA, 9, com.lowagie.text.Font.NORMAL);

            // Données
            for (MembreResponse membre : membres) {
                if (inclurePerso) {
                    table.addCell(createDataCell(membre.getNom() != null ? membre.getNom() : "", dataFont));
                    table.addCell(createDataCell(membre.getPrenom() != null ? membre.getPrenom() : "", dataFont));
                    String dateNaissance = "";
                    if (membre.getDateNaissance() != null) {
                        dateNaissance = formaterDates
                                ? membre.getDateNaissance().format(DATE_FORMATTER)
                                : membre.getDateNaissance().toString();
                    }
                    table.addCell(createDataCell(dateNaissance, dataFont));
                }
                if (inclureContact) {
                    table.addCell(createDataCell(membre.getEmail() != null ? membre.getEmail() : "", dataFont));
                    table.addCell(createDataCell(membre.getTelephone() != null ? membre.getTelephone() : "", dataFont));
                }
                if (inclureAdhesion) {
                    table.addCell(createDataCell("", dataFont)); // Date adhésion (pas dans DTO)
                    table.addCell(createDataCell(membre.getStatutCompte() != null ? membre.getStatutCompte() : "", dataFont));
                }
                if (inclureOrg) {
                    table.addCell(createDataCell(membre.getOrganisationNom() != null ? membre.getOrganisationNom() : "", dataFont));
                }
            }

            document.add(table);

            // Ajouter statistiques si demandé
            if (inclureStatistiques && !membres.isEmpty()) {
                document.newPage();
                ajouterStatistiquesPDF(document, membres);
            }

            document.close();
            return outputStream.toByteArray();
        }
    }

    /**
     * Crée une cellule d'en-tête PDF
     */
    private PdfPCell createHeaderCell(String text, com.lowagie.text.Font font, Color bgColor) {
        PdfPCell cell = new PdfPCell(new Phrase(text, font));
        cell.setBackgroundColor(bgColor);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setPadding(8);
        return cell;
    }

    /**
     * Crée une cellule de données PDF
     */
    private PdfPCell createDataCell(String text, com.lowagie.text.Font font) {
        PdfPCell cell = new PdfPCell(new Phrase(text, font));
        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setPadding(5);
        return cell;
    }

    /**
     * Ajoute une page de statistiques au PDF
     */
    private void ajouterStatistiquesPDF(Document document, java.util.List<MembreResponse> membres) throws DocumentException {
        // Titre section statistiques
        com.lowagie.text.Font titleFont = new com.lowagie.text.Font(com.lowagie.text.Font.HELVETICA, 16, com.lowagie.text.Font.BOLD, Color.DARK_GRAY);
        Paragraph statsTitle = new Paragraph("Statistiques des Membres", titleFont);
        statsTitle.setAlignment(Element.ALIGN_CENTER);
        statsTitle.setSpacingAfter(20);
        document.add(statsTitle);

        // Calcul des statistiques
        long totalMembres = membres.size();
        long membresActifs = membres.stream()
                .filter(m -> dev.lions.unionflow.server.api.enums.membre.StatutMembre.ACTIF.name()
                        .equals(m.getStatutCompte()))
                .count();
        long membresInactifs = membres.stream()
                .filter(m -> dev.lions.unionflow.server.api.enums.membre.StatutMembre.INACTIF.name()
                        .equals(m.getStatutCompte()))
                .count();
        long membresSuspendus = membres.stream()
                .filter(m -> dev.lions.unionflow.server.api.enums.membre.StatutMembre.SUSPENDU.name()
                        .equals(m.getStatutCompte()))
                .count();
        long organisationsDistinctes = membres.stream()
                .filter(m -> m.getOrganisationNom() != null)
                .map(MembreResponse::getOrganisationNom)
                .distinct()
                .count();

        // Créer tableau statistiques
        PdfPTable statsTable = new PdfPTable(2);
        statsTable.setWidthPercentage(60);
        statsTable.setHorizontalAlignment(Element.ALIGN_CENTER);
        statsTable.setSpacingBefore(10);

        com.lowagie.text.Font labelFont = new com.lowagie.text.Font(com.lowagie.text.Font.HELVETICA, 11, com.lowagie.text.Font.BOLD);
        com.lowagie.text.Font valueFont = new com.lowagie.text.Font(com.lowagie.text.Font.HELVETICA, 11, com.lowagie.text.Font.NORMAL);

        // Ajouter lignes
        statsTable.addCell(createStatsCell("Total Membres", labelFont, true));
        statsTable.addCell(createStatsCell(String.valueOf(totalMembres), valueFont, false));

        statsTable.addCell(createStatsCell("Membres Actifs", labelFont, true));
        statsTable.addCell(createStatsCell(String.valueOf(membresActifs), valueFont, false));

        statsTable.addCell(createStatsCell("Membres Inactifs", labelFont, true));
        statsTable.addCell(createStatsCell(String.valueOf(membresInactifs), valueFont, false));

        statsTable.addCell(createStatsCell("Membres Suspendus", labelFont, true));
        statsTable.addCell(createStatsCell(String.valueOf(membresSuspendus), valueFont, false));

        statsTable.addCell(createStatsCell("Organisations Distinctes", labelFont, true));
        statsTable.addCell(createStatsCell(String.valueOf(organisationsDistinctes), valueFont, false));

        document.add(statsTable);
    }

    /**
     * Crée une cellule de statistiques PDF
     */
    private PdfPCell createStatsCell(String text, com.lowagie.text.Font font, boolean isLabel) {
        PdfPCell cell = new PdfPCell(new Phrase(text, font));
        cell.setHorizontalAlignment(isLabel ? Element.ALIGN_LEFT : Element.ALIGN_RIGHT);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setPadding(8);
        if (isLabel) {
            cell.setBackgroundColor(new Color(236, 240, 241)); // Gris clair
        }
        return cell;
    }

    /**
     * Génère un modèle Excel pour l'import
     */
    public byte[] genererModeleImport() throws IOException {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("Modèle");

            // En-têtes
            Row headerRow = sheet.createRow(0);
            headerRow.createCell(0).setCellValue("Nom");
            headerRow.createCell(1).setCellValue("Prénom");
            headerRow.createCell(2).setCellValue("Email");
            headerRow.createCell(3).setCellValue("Téléphone");
            headerRow.createCell(4).setCellValue("Date naissance");
            headerRow.createCell(5).setCellValue("Date adhésion");
            headerRow.createCell(6).setCellValue("Adresse");
            headerRow.createCell(7).setCellValue("Profession");
            headerRow.createCell(8).setCellValue("Type membre");

            // Exemple de ligne
            Row exampleRow = sheet.createRow(1);
            exampleRow.createCell(0).setCellValue("DUPONT");
            exampleRow.createCell(1).setCellValue("Jean");
            exampleRow.createCell(2).setCellValue("jean.dupont@example.com");
            exampleRow.createCell(3).setCellValue("+225 07 12 34 56 78");
            exampleRow.createCell(4).setCellValue("15/01/1990");
            exampleRow.createCell(5).setCellValue("01/01/2024");
            exampleRow.createCell(6).setCellValue("Abidjan, Cocody");
            exampleRow.createCell(7).setCellValue("Ingénieur");
            exampleRow.createCell(8).setCellValue("ACTIF");

            // Auto-size columns
            for (int i = 0; i < 9; i++) {
                sheet.autoSizeColumn(i);
            }

            // Écrire dans un ByteArrayOutputStream
            try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                workbook.write(outputStream);
                return outputStream.toByteArray();
            }
        }
    }

    /**
     * Classe pour le résultat de l'import
     */
    public static class ResultatImport {
        public int totalLignes;
        public int lignesTraitees;
        public int lignesErreur;
        public List<String> erreurs;
        public List<MembreResponse> membresImportes;
    }
}
