package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.entity.Cotisation;
import dev.lions.unionflow.server.repository.CotisationRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * Service d'export des données en Excel et PDF
 * 
 * @author UnionFlow Team
 * @version 1.0
 */
@ApplicationScoped
public class ExportService {

    private static final Logger LOG = Logger.getLogger(ExportService.class);
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");
    private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");

    @Inject
    CotisationRepository cotisationRepository;

    @Inject
    CotisationService cotisationService;

    /**
     * Exporte les cotisations en format CSV (compatible Excel)
     */
    public byte[] exporterCotisationsCSV(List<UUID> cotisationIds) {
        LOG.infof("Export CSV de %d cotisations", cotisationIds.size());

        StringBuilder csv = new StringBuilder();
        csv.append(
                "Numéro Référence;Membre;Type;Montant Dû;Montant Payé;Statut;Date Échéance;Date Paiement;Méthode Paiement\n");

        for (UUID id : cotisationIds) {
            Optional<Cotisation> cotisationOpt = cotisationRepository.findByIdOptional(id);
            if (cotisationOpt.isPresent()) {
                Cotisation c = cotisationOpt.get();
                String nomMembre = c.getMembre() != null
                        ? c.getMembre().getNom() + " " + c.getMembre().getPrenom()
                        : "";
                csv.append(String.format("%s;%s;%s;%s;%s;%s;%s;%s;%s\n",
                        c.getNumeroReference() != null ? c.getNumeroReference() : "",
                        nomMembre,
                        c.getTypeCotisation() != null ? c.getTypeCotisation() : "",
                        c.getMontantDu() != null ? c.getMontantDu().toString() : "0",
                        c.getMontantPaye().toString(),
                        c.getStatut() != null ? c.getStatut() : "",
                        c.getDateEcheance() != null ? c.getDateEcheance().format(DATE_FORMATTER) : "",
                        c.getDatePaiement() != null ? c.getDatePaiement().format(DATETIME_FORMATTER) : "",
                        "WAVE"));
            }
        }

        return csv.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
    }

    /**
     * Exporte toutes les cotisations filtrées en CSV
     */
    public byte[] exporterToutesCotisationsCSV(String statut, String type, UUID associationId) {
        LOG.info("Export CSV de toutes les cotisations");

        List<Cotisation> cotisations = cotisationRepository.listAll();

        // Filtrer
        if (statut != null && !statut.isEmpty()) {
            cotisations = cotisations.stream()
                    .filter(c -> c.getStatut() != null && c.getStatut().equals(statut))
                    .toList();
        }
        if (type != null && !type.isEmpty()) {
            cotisations = cotisations.stream()
                    .filter(c -> c.getTypeCotisation() != null && c.getTypeCotisation().equals(type))
                    .toList();
        }
        // Note: le filtrage par association n'est pas disponible car Membre n'a pas de
        // lien direct
        // avec Association dans cette version du modèle

        List<UUID> ids = cotisations.stream().map(Cotisation::getId).toList();
        return exporterCotisationsCSV(ids);
    }

    /**
     * Génère un reçu de paiement en format texte (pour impression)
     */
    public byte[] genererRecuPaiement(UUID cotisationId) {
        LOG.infof("Génération reçu pour cotisation: %s", cotisationId);

        Optional<Cotisation> cotisationOpt = cotisationRepository.findByIdOptional(cotisationId);
        if (cotisationOpt.isEmpty()) {
            return "Cotisation non trouvée".getBytes();
        }

        Cotisation c = cotisationOpt.get();

        StringBuilder recu = new StringBuilder();
        recu.append("═══════════════════════════════════════════════════════════════\n");
        recu.append("                         REÇU DE PAIEMENT\n");
        recu.append("═══════════════════════════════════════════════════════════════\n\n");

        recu.append("Numéro de reçu    : ").append(c.getNumeroReference()).append("\n");
        recu.append("Date              : ").append(LocalDateTime.now().format(DATETIME_FORMATTER)).append("\n\n");

        recu.append("───────────────────────────────────────────────────────────────\n");
        recu.append("                       INFORMATIONS MEMBRE\n");
        recu.append("───────────────────────────────────────────────────────────────\n");

        if (c.getMembre() != null) {
            recu.append("Nom               : ").append(c.getMembre().getNom()).append(" ")
                    .append(c.getMembre().getPrenom()).append("\n");
            recu.append("Numéro membre     : ").append(c.getMembre().getNumeroMembre()).append("\n");
        }

        recu.append("\n───────────────────────────────────────────────────────────────\n");
        recu.append("                      DÉTAILS DU PAIEMENT\n");
        recu.append("───────────────────────────────────────────────────────────────\n");

        recu.append("Type cotisation   : ").append(c.getTypeCotisation() != null ? c.getTypeCotisation() : "")
                .append("\n");
        recu.append("Période           : ").append(c.getPeriode() != null ? c.getPeriode() : "").append("\n");
        recu.append("Montant dû        : ").append(formatMontant(c.getMontantDu())).append("\n");
        recu.append("Montant payé      : ").append(formatMontant(c.getMontantPaye())).append("\n");
        recu.append("Mode de paiement  : Wave Money\n");
        recu.append("Date de paiement  : ")
                .append(c.getDatePaiement() != null ? c.getDatePaiement().format(DATETIME_FORMATTER) : "").append("\n");
        recu.append("Statut            : ").append(c.getStatut() != null ? c.getStatut() : "").append("\n");

        recu.append("\n═══════════════════════════════════════════════════════════════\n");
        recu.append("          Ce document fait foi de paiement de cotisation\n");
        recu.append("                     Merci de votre confiance !\n");
        recu.append("═══════════════════════════════════════════════════════════════\n");

        return recu.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
    }

    /**
     * Génère plusieurs reçus de paiement
     */
    public byte[] genererRecusGroupes(List<UUID> cotisationIds) {
        LOG.infof("Génération de %d reçus groupés", cotisationIds.size());

        StringBuilder allRecus = new StringBuilder();
        for (int i = 0; i < cotisationIds.size(); i++) {
            byte[] recu = genererRecuPaiement(cotisationIds.get(i));
            allRecus.append(new String(recu, java.nio.charset.StandardCharsets.UTF_8));
            if (i < cotisationIds.size() - 1) {
                allRecus.append("\n\n════════════════════════ PAGE SUIVANTE ════════════════════════\n\n");
            }
        }

        return allRecus.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
    }

    /**
     * Génère un rapport mensuel
     */
    public byte[] genererRapportMensuel(int annee, int mois, UUID associationId) {
        LOG.infof("Génération rapport mensuel: %d/%d", mois, annee);

        List<Cotisation> cotisations = cotisationRepository.listAll();

        // Filtrer par mois/année et association
        LocalDate debut = LocalDate.of(annee, mois, 1);
        LocalDate fin = debut.plusMonths(1).minusDays(1);

        cotisations = cotisations.stream()
                .filter(c -> {
                    if (c.getDateCreation() == null)
                        return false;
                    LocalDate dateCot = c.getDateCreation().toLocalDate();
                    return !dateCot.isBefore(debut) && !dateCot.isAfter(fin);
                })
                // Note: le filtrage par association n'est pas implémenté ici
                .toList();

        // Calculer les statistiques
        long total = cotisations.size();
        long payees = cotisations.stream().filter(c -> "PAYEE".equals(c.getStatut())).count();
        long enAttente = cotisations.stream().filter(c -> "EN_ATTENTE".equals(c.getStatut())).count();
        long enRetard = cotisations.stream().filter(c -> "EN_RETARD".equals(c.getStatut())).count();

        BigDecimal montantTotal = cotisations.stream()
                .map(c -> c.getMontantDu() != null ? c.getMontantDu() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal montantCollecte = cotisations.stream()
                .filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
                .map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        double tauxRecouvrement = montantTotal.compareTo(BigDecimal.ZERO) > 0
                ? montantCollecte.multiply(BigDecimal.valueOf(100))
                        .divide(montantTotal, 2, java.math.RoundingMode.HALF_UP).doubleValue()
                : 0;

        // Construire le rapport
        StringBuilder rapport = new StringBuilder();
        rapport.append("═══════════════════════════════════════════════════════════════\n");
        rapport.append("                    RAPPORT MENSUEL DES COTISATIONS\n");
        rapport.append("═══════════════════════════════════════════════════════════════\n\n");

        rapport.append("Période           : ").append(String.format("%02d/%d", mois, annee)).append("\n");
        rapport.append("Date de génération: ").append(LocalDateTime.now().format(DATETIME_FORMATTER)).append("\n\n");

        rapport.append("───────────────────────────────────────────────────────────────\n");
        rapport.append("                         RÉSUMÉ\n");
        rapport.append("───────────────────────────────────────────────────────────────\n\n");

        rapport.append("Total cotisations     : ").append(total).append("\n");
        rapport.append("Cotisations payées    : ").append(payees).append("\n");
        rapport.append("Cotisations en attente: ").append(enAttente).append("\n");
        rapport.append("Cotisations en retard : ").append(enRetard).append("\n\n");

        rapport.append("───────────────────────────────────────────────────────────────\n");
        rapport.append("                       FINANCIER\n");
        rapport.append("───────────────────────────────────────────────────────────────\n\n");

        rapport.append("Montant total attendu : ").append(formatMontant(montantTotal)).append("\n");
        rapport.append("Montant collecté      : ").append(formatMontant(montantCollecte)).append("\n");
        rapport.append("Taux de recouvrement  : ").append(String.format("%.1f%%", tauxRecouvrement)).append("\n\n");

        rapport.append("═══════════════════════════════════════════════════════════════\n");

        return rapport.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
    }

    private String formatMontant(BigDecimal montant) {
        if (montant == null)
            return "0 FCFA";
        return String.format("%,.0f FCFA", montant.doubleValue());
    }

    /** Alias PDF pour la compatibilité avec ExportResource */
    public byte[] genererRecuPaiementPDF(java.util.UUID cotisationId) {
        return genererRecuPaiement(cotisationId);
    }

    /** Alias PDF pour la compatibilité avec ExportResource */
    public byte[] genererRapportMensuelPDF(int annee, int mois, java.util.UUID associationId) {
        return genererRapportMensuel(annee, mois, associationId);
    }
}
