package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.dashboard.MembreDashboardSyntheseResponse;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.repository.CotisationRepository;
import dev.lions.unionflow.server.repository.DemandeAideRepository;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.mutuelle.epargne.CompteEpargneRepository;
import dev.lions.unionflow.server.service.support.SecuriteHelper;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.NotFoundException;
import org.jboss.logging.Logger;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;


@ApplicationScoped
public class MembreDashboardService {

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

    @Inject
    SecuriteHelper securiteHelper;

    @Inject
    MembreRepository membreRepository;

    @Inject
    CotisationRepository cotisationRepository;

    @Inject
    CompteEpargneRepository compteEpargneRepository;

    @Inject
    DemandeAideRepository demandeAideRepository;

    public MembreDashboardSyntheseResponse getDashboardData() {
        String email = securiteHelper.resolveEmail();

        if (email == null || email.isBlank()) {
            throw new NotFoundException("Identité non disponible pour le dashboard membre.");
        }
        LOG.infof("Génération du dashboard pour le membre: %s", email);

        Membre membre = membreRepository.findByEmail(email.trim())
                .or(() -> membreRepository.findByEmail(email.trim().toLowerCase()))
                .filter(m -> m.getActif() == null || m.getActif())
                .orElseThrow(() -> new NotFoundException("Membre non trouvé pour l'email: " + email));

        UUID membreId = membre.getId();

        // 1. Infos membre
        String prenom = membre.getPrenom();
        String nom = membre.getNom();
        LocalDate dateInscription = null;
        if (membre.getDateCreation() != null) {
            dateInscription = membre.getDateCreation().toLocalDate();
        }

        // 2. Cotisations
        // Approximations : on somme les cotisations payées ce mois, on regarde s'il y a
        // des cotisations en retard, etc.
        // On utilisera des méthodes custom sur le repository si besoin, ou on le fait
        // en Java (sur les petits sets test)
        BigDecimal paiementsMois = cotisationRepository.calculerTotalCotisationsPayeesCeMois(membreId);

        // Statut : "En retard", "À jour", "En attente"
        long enRetardCount = cotisationRepository.countRetardByMembreId(membreId);
        String statutCotisations = enRetardCount > 0 ? "En retard" : "À jour";

        // Taux de cotisation (payé vs dû pour l'année en cours)
        BigDecimal totalAnneeDu = cotisationRepository.calculerTotalCotisationsAnneeEnCours(membreId);
        BigDecimal totalAnneePaye = cotisationRepository.calculerTotalCotisationsPayeesAnneeEnCours(membreId);

        Integer tauxCotisations;
        if (totalAnneeDu != null && totalAnneeDu.compareTo(BigDecimal.ZERO) > 0) {
            // Cas normal : cotisations prévues pour l'année courante
            if (totalAnneePaye == null) totalAnneePaye = BigDecimal.ZERO;
            tauxCotisations = totalAnneePaye.multiply(new BigDecimal("100"))
                    .divide(totalAnneeDu, 0, java.math.RoundingMode.HALF_UP)
                    .intValue();
        } else {
            // Fallback : aucune cotisation prévue cette année (ex: cotisation annuelle payée les années précédentes)
            // On regarde le statut global : en retard = 0%, sinon on regarde tout temps
            long totalToutesAnneesCount = cotisationRepository.countByMembreId(membreId);
            long payeesToutTempsCount = cotisationRepository.countPayeesByMembreId(membreId);
            long retardToutTemps = cotisationRepository.countRetardByMembreId(membreId);

            if (totalToutesAnneesCount == 0) {
                tauxCotisations = null; // Aucune cotisation du tout
            } else if (retardToutTemps > 0) {
                // Il y a des cotisations en retard : taux partiel
                tauxCotisations = (int) (payeesToutTempsCount * 100L / totalToutesAnneesCount);
            } else {
                // Tout est à jour (payées et échéances futures) : 100%
                tauxCotisations = 100;
            }
        }

        BigDecimal totalCotisationsPayeesAnnee = (totalAnneePaye != null ? totalAnneePaye : BigDecimal.ZERO);
        BigDecimal totalCotisationsPayeesToutTemps = cotisationRepository.calculerTotalCotisationsPayeesToutTemps(membreId);
        int nombreCotisationsPayees = (int) cotisationRepository.countPayeesByMembreId(membreId);
        // Nombre total toutes années confondues (pour la mobile app)
        int nombreCotisationsTotal = (int) cotisationRepository.countByMembreId(membreId);

        // 3. Epargne (somme des soldes des comptes actifs du membre)
        BigDecimal soldeEpargne = compteEpargneRepository.sumSoldeActuelByMembreId(membreId);
        BigDecimal evolutionEpargneNb = BigDecimal.ZERO;
        String evolutionEpargneTxt = soldeEpargne.compareTo(BigDecimal.ZERO) > 0 ? "+0%" : "0%";
        Integer objectifEpargne = 0;

        // 4. Événements (pas de repository InscriptionEvenement dédié pour l'instant)
        Integer mesEvenements = 0;
        Integer evenementsAVenir = 0;
        Integer tauxParticipation = null;

        // 5. Aides (demandes du membre)
        List<dev.lions.unionflow.server.entity.DemandeAide> demandes = demandeAideRepository.findByDemandeurId(membreId);
        int mesDemandes = demandes != null ? demandes.size() : 0;
        int aidesCours = demandes != null ? (int) demandes.stream()
                .filter(d -> d.getStatut() != null && d.getStatut() != StatutAide.APPROUVEE && d.getStatut() != StatutAide.REJETEE && d.getStatut() != StatutAide.ANNULEE)
                .count() : 0;
        Integer tauxAidesApprouvees = null;
        if (mesDemandes > 0) {
            long acceptees = demandes.stream().filter(d -> d.getStatut() == StatutAide.APPROUVEE).count();
            tauxAidesApprouvees = (int) (acceptees * 100 / mesDemandes);
        }

        return new MembreDashboardSyntheseResponse(
                prenom,
                nom,
                dateInscription,

                paiementsMois != null ? paiementsMois : BigDecimal.ZERO,
                totalCotisationsPayeesAnnee,
                totalCotisationsPayeesToutTemps != null ? totalCotisationsPayeesToutTemps : BigDecimal.ZERO,
                Integer.valueOf(nombreCotisationsPayees),
                statutCotisations,
                tauxCotisations,           // Maintenant valide pour tous les membres
                Integer.valueOf(nombreCotisationsTotal),  // Nouveau : total toutes années

                soldeEpargne,
                evolutionEpargneNb,
                evolutionEpargneTxt,
                objectifEpargne,

                mesEvenements,
                evenementsAVenir,
                tauxParticipation,

                Integer.valueOf(mesDemandes),
                Integer.valueOf(aidesCours),
                tauxAidesApprouvees);
    }
}
