package dev.lions.unionflow.client.view;

import dev.lions.unionflow.client.constants.ViewPaths;
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
import dev.lions.unionflow.server.api.dto.cotisation.response.CotisationResponse;
import dev.lions.unionflow.server.api.dto.evenement.response.EvenementResponse;
import dev.lions.unionflow.client.service.MembreService;
import dev.lions.unionflow.client.service.CotisationService;
import dev.lions.unionflow.client.service.EvenementService;
import dev.lions.unionflow.client.service.ErrorHandlerService;
import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
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.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

@Named("membreDashboardBean")
@SessionScoped
public class MembreDashboardBean implements Serializable {

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

    @Inject
    private UserSession userSession;

    @Inject
    @RestClient
    private MembreService membreService;

    @Inject
    @RestClient
    private CotisationService cotisationService;

    @Inject
    @RestClient
    private EvenementService evenementService;

    @Inject
    ErrorHandlerService errorHandler;

    // Membre actuel (DTO backend)
    private MembreResponse membre;

    // Statistiques calculées
    private String statutCotisations;
    private int evenementsInscrits;
    private int aidesRecues;
    private int messagesNonLus;

    // Progression cotisations
    private int cotisationsPayees;
    private int cotisationsTotales;
    private int progressionCotisations;
    private int tauxParticipation;
    private int evenementsAssistes;
    private String anciennete;
    private String dateAdhesionFormatee;

    // Listes
    private List<Alerte> alertes = new ArrayList<>();
    private List<Evenement> prochainsEvenements = new ArrayList<>();
    private List<Rappel> rappels = new ArrayList<>();
    private List<Activite> activiteRecente = new ArrayList<>();

    // État
    private boolean peutPayerCotisations;

    @PostConstruct
    public void init() {
        chargerMembre();
        chargerCotisations();
        chargerEvenements();
        construireRappels();
    }

    // ── Chargement des données réelles ──────────────────────────────────────

    /**
     * Charge le membre connecté depuis le backend.
     */
    private void chargerMembre() {
        try {
            membre = membreService.obtenirMembreConnecte();
            if (membre == null) {
                LOG.warn("Aucun profil membre retourné par /api/membres/me");
            } else {
                LOG.infof("Dashboard membre chargé pour: %s", membre.getNomComplet());
                // Date d'adhésion formatée
                if (membre.getDateAdhesion() != null) {
                    dateAdhesionFormatee = membre.getDateAdhesion()
                            .format(DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.FRENCH));
                    anciennete = calculerAnciennete(membre.getDateAdhesion());
                }
            }
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du chargement du membre connecté");
            errorHandler.handleException(e, "lors du chargement du tableau de bord membre", null);
        }
    }

    /**
     * Charge et calcule les statistiques de cotisations.
     */
    private void chargerCotisations() {
        alertes = new ArrayList<>();
        activiteRecente = new ArrayList<>();
        cotisationsPayees = 0;
        cotisationsTotales = 0;
        progressionCotisations = 0;
        statutCotisations = "Inconnu";
        peutPayerCotisations = false;

        if (membre == null) return;

        try {
            List<CotisationResponse> cotisations = cotisationService.obtenirParMembre(membre.getId(), 0, 50);
            if (cotisations == null || cotisations.isEmpty()) {
                statutCotisations = "Aucune cotisation";
                return;
            }

            cotisationsTotales = cotisations.size();
            long payees = cotisations.stream().filter(c -> "PAYEE".equals(c.getStatut())).count();
            long enAttente = cotisations.stream().filter(c -> "EN_ATTENTE".equals(c.getStatut()) || "PARTIELLE".equals(c.getStatut())).count();
            cotisationsPayees = (int) payees;

            progressionCotisations = cotisationsTotales > 0
                    ? (int) Math.round(payees * 100.0 / cotisationsTotales)
                    : 0;

            if (enAttente == 0) {
                statutCotisations = "À jour";
            } else {
                statutCotisations = enAttente + " en attente";
                peutPayerCotisations = true;
            }

            // Activité récente : 5 dernières cotisations
            int limite = Math.min(5, cotisations.size());
            for (int i = 0; i < limite; i++) {
                CotisationResponse cot = cotisations.get(i);
                Activite act = new Activite();
                String libelleStatut = cot.getStatutLibelle() != null ? cot.getStatutLibelle() : cot.getStatut();
                act.setTitre("Cotisation " + libelleStatut);
                act.setDescription(cot.getMontantDuFormatte() +
                        (cot.getPeriode() != null ? " – " + cot.getPeriode() : ""));
                act.setDateRelative(cot.getDatePaiement() != null
                        ? formatDateRelative(cot.getDatePaiement().toLocalDate())
                        : (cot.getDateCreation() != null
                                ? formatDateRelative(cot.getDateCreation().toLocalDate())
                                : "Récemment"));
                act.setIcone("pi-dollar");
                act.setCouleurCategorie("bg-green-500");
                activiteRecente.add(act);
            }

            // Alertes pour cotisations en retard ou en attente
            cotisations.stream()
                    .filter(c -> "EN_RETARD".equals(c.getStatut()) || "EN_ATTENTE".equals(c.getStatut()))
                    .limit(3)
                    .forEach(cot -> {
                        Alerte alerte = new Alerte();
                        alerte.setTitre("Cotisation " + (cot.getStatutLibelle() != null ? cot.getStatutLibelle() : cot.getStatut()));
                        alerte.setMessage("Montant : " + cot.getMontantDuFormatte() +
                                (cot.getDateEcheance() != null
                                        ? " – Échéance : " + cot.getDateEcheance().format(DateTimeFormatter.ofPattern("dd/MM/yyyy"))
                                        : ""));
                        alerte.setDateRelative(cot.getDateEcheance() != null
                                ? formatDateRelative(cot.getDateEcheance())
                                : "");
                        alerte.setIcone("pi-dollar");
                        alerte.setCouleurIcone("text-orange-500");
                        alerte.setCouleurFond("rgba(255, 193, 7, 0.1)");
                        alerte.setCouleurBordure("border-orange-500");
                        alertes.add(alerte);
                    });

        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du chargement des cotisations pour le dashboard");
            errorHandler.handleException(e, "lors du chargement des cotisations", null);
        }
    }

    /**
     * Charge les prochains événements depuis le backend.
     */
    private void chargerEvenements() {
        prochainsEvenements = new ArrayList<>();
        evenementsInscrits = 0;

        try {
            var response = evenementService.listerAVenir(0, 5);
            if (response == null || response.getData() == null) return;

            evenementsInscrits = response.getData().size();

            for (EvenementResponse evt : response.getData()) {
                Evenement evenement = new Evenement();
                evenement.setTitre(evt.getTitre() != null ? evt.getTitre() : "Événement");

                // Date formatée
                String dateComplete = "";
                if (evt.getDateDebut() != null) {
                    DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEEE d MMMM yyyy", Locale.FRENCH);
                    dateComplete = evt.getDateDebut().format(fmt);
                    if (evt.getHeureDebut() != null) {
                        dateComplete += " – " + evt.getHeureDebut().format(DateTimeFormatter.ofPattern("HH'h'mm"));
                    }
                }
                evenement.setDateComplete(dateComplete);
                evenement.setLieu(evt.getLieu() != null ? evt.getLieu() : (evt.getVille() != null ? evt.getVille() : "À définir"));

                // Prix
                if (evt.getBudget() == null || evt.getBudget().signum() == 0) {
                    evenement.setPrixFormate("Gratuit");
                } else {
                    evenement.setPrixFormate(String.format(Locale.US, "%,.0f %s",
                            evt.getBudget(),
                            evt.getCodeDevise() != null ? evt.getCodeDevise() : "FCFA"));
                }

                // Participants
                int nb = evt.getParticipantsInscrits() != null ? evt.getParticipantsInscrits() : 0;
                evenement.setNombreParticipants(nb + " inscrits");

                // Statut d'inscription par défaut
                evenement.setStatutInscription("Ouvert");
                evenement.setSeverityInscription("info");
                evenement.setPeutAnnuler(false);

                // Icône et couleur selon type
                if (evt.getTypeEvenement() != null) {
                    switch (evt.getTypeEvenement().name()) {
                        case "ASSEMBLEE_GENERALE":
                            evenement.setIconeType("pi-users");
                            evenement.setCouleurCategorie("bg-blue-500");
                            evenement.setCouleurBordure("border-blue-500");
                            break;
                        case "FORMATION":
                            evenement.setIconeType("pi-book");
                            evenement.setCouleurCategorie("bg-purple-500");
                            evenement.setCouleurBordure("border-purple-500");
                            break;
                        case "SORTIE":
                        case "ACTIVITE_SOCIALE":
                            evenement.setIconeType("pi-car");
                            evenement.setCouleurCategorie("bg-green-500");
                            evenement.setCouleurBordure("border-green-500");
                            break;
                        default:
                            evenement.setIconeType("pi-calendar");
                            evenement.setCouleurCategorie("bg-blue-500");
                            evenement.setCouleurBordure("border-blue-500");
                    }
                } else {
                    evenement.setIconeType("pi-calendar");
                    evenement.setCouleurCategorie("bg-blue-500");
                    evenement.setCouleurBordure("border-blue-500");
                }

                prochainsEvenements.add(evenement);
            }

            // Ajouter les événements à venir comme activité récente
            for (EvenementResponse evt : response.getData()) {
                Activite act = new Activite();
                act.setTitre("Événement à venir : " + (evt.getTitre() != null ? evt.getTitre() : ""));
                act.setDescription(evt.getLieu() != null ? evt.getLieu() : "");
                act.setDateRelative(evt.getDateDebut() != null
                        ? formatDateRelative(evt.getDateDebut())
                        : "Bientôt");
                act.setIcone("pi-calendar");
                act.setCouleurCategorie("bg-blue-500");
                activiteRecente.add(act);
            }

            // Nombre d'événements assistés (statistique du membre si disponible)
            if (membre != null) {
                evenementsAssistes = membre.getNombreEvenementsParticipes();
                tauxParticipation = cotisationsTotales > 0
                        ? progressionCotisations
                        : 0;
            }

        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du chargement des événements pour le dashboard");
            errorHandler.handleException(e, "lors du chargement des événements", null);
        }
    }

    /**
     * Construit les rappels à partir des cotisations en attente et des événements imminents.
     */
    private void construireRappels() {
        rappels = new ArrayList<>();

        // Rappel cotisations si en attente
        if (peutPayerCotisations) {
            Rappel rappel = new Rappel();
            rappel.setTitre("Cotisation(s) en attente");
            rappel.setEcheance("À régler dès que possible");
            rappel.setIcone("pi-dollar");
            rappel.setCouleurIcone("text-orange-500");
            rappel.setCouleurFond("surface-100");
            rappels.add(rappel);
        }

        // Rappels événements imminents (dans les 7 prochains jours)
        for (Evenement evt : prochainsEvenements) {
            // On essaie d'ajouter un rappel pour chaque événement proche
            Rappel rappel = new Rappel();
            rappel.setTitre(evt.getTitre());
            rappel.setEcheance(evt.getDateComplete());
            rappel.setIcone("pi-calendar");
            rappel.setCouleurIcone("text-blue-500");
            rappel.setCouleurFond("surface-100");
            rappels.add(rappel);
            if (rappels.size() >= 3) break;
        }
    }

    // ── Utilitaires ─────────────────────────────────────────────────────────

    private String calculerAnciennete(LocalDate dateAdhesion) {
        long annees = ChronoUnit.YEARS.between(dateAdhesion, LocalDate.now());
        if (annees == 0) {
            long mois = ChronoUnit.MONTHS.between(dateAdhesion, LocalDate.now());
            return mois <= 1 ? "Moins d'un mois" : mois + " mois";
        }
        return annees + " an" + (annees > 1 ? "s" : "");
    }

    private String formatDateRelative(LocalDate date) {
        if (date == null) return "Récemment";
        long days = ChronoUnit.DAYS.between(date, LocalDate.now());
        if (days < 0) {
            long futur = Math.abs(days);
            if (futur == 1) return "Demain";
            if (futur < 7) return "Dans " + futur + " jours";
            if (futur < 30) return "Dans " + (futur / 7) + " semaine" + (futur / 7 > 1 ? "s" : "");
            return "Dans " + (futur / 30) + " mois";
        }
        if (days == 0) return "Aujourd'hui";
        if (days == 1) return "Hier";
        if (days < 7) return "Il y a " + days + " jour" + (days > 1 ? "s" : "");
        if (days < 30) return "Il y a " + (days / 7) + " semaine" + (days / 7 > 1 ? "s" : "");
        long mois = days / 30;
        return "Il y a " + mois + " mois";
    }

    // ── Actions ─────────────────────────────────────────────────────────────

    public void marquerLue(Alerte alerte) {
        alertes.remove(alerte);
    }

    public String voirEvenement(Evenement evenement) {
        return ViewPaths.EVENEMENT_GESTION + ".xhtml" + ViewPaths.REDIRECT_SUFFIX;
    }

    public void annulerInscription(Evenement evenement) {
        evenement.setStatutInscription("Annulé");
        evenement.setSeverityInscription("danger");
        evenement.setPeutAnnuler(false);
    }

    public String payerCotisations() {
        return ViewPaths.COTISATION_PAIEMENT + ".xhtml" + ViewPaths.REDIRECT_SUFFIX;
    }

    public void actualiser() {
        chargerMembre();
        chargerCotisations();
        chargerEvenements();
        construireRappels();
        errorHandler.showSuccess("Succès", "Données actualisées.");
    }

    // ── Getters et Setters ───────────────────────────────────────────────────

    public MembreResponse getMembre() { return membre; }
    public void setMembre(MembreResponse membre) { this.membre = membre; }

    public String getStatutCotisations() { return statutCotisations; }
    public void setStatutCotisations(String statutCotisations) { this.statutCotisations = statutCotisations; }

    public int getEvenementsInscrits() { return evenementsInscrits; }
    public void setEvenementsInscrits(int evenementsInscrits) { this.evenementsInscrits = evenementsInscrits; }

    public int getAidesRecues() { return aidesRecues; }
    public void setAidesRecues(int aidesRecues) { this.aidesRecues = aidesRecues; }

    public int getMessagesNonLus() { return messagesNonLus; }
    public void setMessagesNonLus(int messagesNonLus) { this.messagesNonLus = messagesNonLus; }

    public int getCotisationsPayees() { return cotisationsPayees; }
    public void setCotisationsPayees(int cotisationsPayees) { this.cotisationsPayees = cotisationsPayees; }

    public int getCotisationsTotales() { return cotisationsTotales; }
    public void setCotisationsTotales(int cotisationsTotales) { this.cotisationsTotales = cotisationsTotales; }

    public int getProgressionCotisations() { return progressionCotisations; }
    public void setProgressionCotisations(int progressionCotisations) { this.progressionCotisations = progressionCotisations; }

    public int getTauxParticipation() { return tauxParticipation; }
    public void setTauxParticipation(int tauxParticipation) { this.tauxParticipation = tauxParticipation; }

    public int getEvenementsAssistes() { return evenementsAssistes; }
    public void setEvenementsAssistes(int evenementsAssistes) { this.evenementsAssistes = evenementsAssistes; }

    public String getAnciennete() { return anciennete; }
    public void setAnciennete(String anciennete) { this.anciennete = anciennete; }

    public String getDateAdhesionFormatee() { return dateAdhesionFormatee; }
    public void setDateAdhesionFormatee(String dateAdhesionFormatee) { this.dateAdhesionFormatee = dateAdhesionFormatee; }

    public List<Alerte> getAlertes() { return alertes; }
    public void setAlertes(List<Alerte> alertes) { this.alertes = alertes; }

    public List<Evenement> getProchainsEvenements() { return prochainsEvenements; }
    public void setProchainsEvenements(List<Evenement> prochainsEvenements) { this.prochainsEvenements = prochainsEvenements; }

    public List<Rappel> getRappels() { return rappels; }
    public void setRappels(List<Rappel> rappels) { this.rappels = rappels; }

    public List<Activite> getActiviteRecente() { return activiteRecente; }
    public void setActiviteRecente(List<Activite> activiteRecente) { this.activiteRecente = activiteRecente; }

    public boolean isPeutPayerCotisations() { return peutPayerCotisations; }
    public void setPeutPayerCotisations(boolean peutPayerCotisations) { this.peutPayerCotisations = peutPayerCotisations; }

    // ── Classes internes ────────────────────────────────────────────────────

    public static class Alerte implements Serializable {
        private String titre;
        private String message;
        private String dateRelative;
        private String icone;
        private String couleurIcone;
        private String couleurFond;
        private String couleurBordure;

        public String getTitre() { return titre; }
        public void setTitre(String titre) { this.titre = titre; }

        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }

        public String getDateRelative() { return dateRelative; }
        public void setDateRelative(String dateRelative) { this.dateRelative = dateRelative; }

        public String getIcone() { return icone; }
        public void setIcone(String icone) { this.icone = icone; }

        public String getCouleurIcone() { return couleurIcone; }
        public void setCouleurIcone(String couleurIcone) { this.couleurIcone = couleurIcone; }

        public String getCouleurFond() { return couleurFond; }
        public void setCouleurFond(String couleurFond) { this.couleurFond = couleurFond; }

        public String getCouleurBordure() { return couleurBordure; }
        public void setCouleurBordure(String couleurBordure) { this.couleurBordure = couleurBordure; }
    }

    public static class Evenement implements Serializable {
        private String titre;
        private String dateComplete;
        private String lieu;
        private String prixFormate;
        private String nombreParticipants;
        private String statutInscription;
        private String severityInscription;
        private String iconeType;
        private String couleurCategorie;
        private String couleurBordure;
        private boolean peutAnnuler;

        public String getTitre() { return titre; }
        public void setTitre(String titre) { this.titre = titre; }

        public String getDateComplete() { return dateComplete; }
        public void setDateComplete(String dateComplete) { this.dateComplete = dateComplete; }

        public String getLieu() { return lieu; }
        public void setLieu(String lieu) { this.lieu = lieu; }

        public String getPrixFormate() { return prixFormate; }
        public void setPrixFormate(String prixFormate) { this.prixFormate = prixFormate; }

        public String getNombreParticipants() { return nombreParticipants; }
        public void setNombreParticipants(String nombreParticipants) { this.nombreParticipants = nombreParticipants; }

        public String getStatutInscription() { return statutInscription; }
        public void setStatutInscription(String statutInscription) { this.statutInscription = statutInscription; }

        public String getSeverityInscription() { return severityInscription; }
        public void setSeverityInscription(String severityInscription) { this.severityInscription = severityInscription; }

        public String getIconeType() { return iconeType; }
        public void setIconeType(String iconeType) { this.iconeType = iconeType; }

        public String getCouleurCategorie() { return couleurCategorie; }
        public void setCouleurCategorie(String couleurCategorie) { this.couleurCategorie = couleurCategorie; }

        public String getCouleurBordure() { return couleurBordure; }
        public void setCouleurBordure(String couleurBordure) { this.couleurBordure = couleurBordure; }

        public boolean isPeutAnnuler() { return peutAnnuler; }
        public void setPeutAnnuler(boolean peutAnnuler) { this.peutAnnuler = peutAnnuler; }

        public String getCouleurPrix() {
            return "Gratuit".equals(prixFormate) ? "text-green-500" : "text-blue-500";
        }
    }

    public static class Rappel implements Serializable {
        private String titre;
        private String echeance;
        private String icone;
        private String couleurIcone;
        private String couleurFond;

        public String getTitre() { return titre; }
        public void setTitre(String titre) { this.titre = titre; }

        public String getEcheance() { return echeance; }
        public void setEcheance(String echeance) { this.echeance = echeance; }

        public String getIcone() { return icone; }
        public void setIcone(String icone) { this.icone = icone; }

        public String getCouleurIcone() { return couleurIcone; }
        public void setCouleurIcone(String couleurIcone) { this.couleurIcone = couleurIcone; }

        public String getCouleurFond() { return couleurFond; }
        public void setCouleurFond(String couleurFond) { this.couleurFond = couleurFond; }
    }

    public static class Activite implements Serializable {
        private String titre;
        private String description;
        private String dateRelative;
        private String icone;
        private String couleurCategorie;

        public String getTitre() { return titre; }
        public void setTitre(String titre) { this.titre = titre; }

        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }

        public String getDateRelative() { return dateRelative; }
        public void setDateRelative(String dateRelative) { this.dateRelative = dateRelative; }

        public String getIcone() { return icone; }
        public void setIcone(String icone) { this.icone = icone; }

        public String getCouleurCategorie() { return couleurCategorie; }
        public void setCouleurCategorie(String couleurCategorie) { this.couleurCategorie = couleurCategorie; }
    }
}
