package dev.lions.unionflow.server.repository;

import dev.lions.unionflow.server.entity.Membre;
import io.quarkus.panache.common.Page;
import io.quarkus.panache.common.Sort;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.persistence.TypedQuery;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/** Repository pour l'entité Membre avec UUID */
@ApplicationScoped
public class MembreRepository extends BaseRepository<Membre> {

    public MembreRepository() {
        super(Membre.class);
    }

    /** Trouve un membre par son email */
    public Optional<Membre> findByEmail(String email) {
        TypedQuery<Membre> query = entityManager.createQuery(
            "SELECT m FROM Membre m WHERE m.email = :email", Membre.class);
        query.setParameter("email", email);
        return query.getResultStream().findFirst();
    }

    /** Trouve un membre par son numéro */
    public Optional<Membre> findByNumeroMembre(String numeroMembre) {
        TypedQuery<Membre> query = entityManager.createQuery(
            "SELECT m FROM Membre m WHERE m.numeroMembre = :numeroMembre", Membre.class);
        query.setParameter("numeroMembre", numeroMembre);
        return query.getResultStream().findFirst();
    }

    /** Trouve tous les membres actifs */
    public List<Membre> findAllActifs() {
        TypedQuery<Membre> query = entityManager.createQuery(
            "SELECT m FROM Membre m WHERE m.actif = true", Membre.class);
        return query.getResultList();
    }

    /** Compte le nombre de membres actifs */
    public long countActifs() {
        TypedQuery<Long> query = entityManager.createQuery(
            "SELECT COUNT(m) FROM Membre m WHERE m.actif = true", Long.class);
        return query.getSingleResult();
    }

    /** Trouve les membres par nom ou prénom (recherche partielle) */
    public List<Membre> findByNomOrPrenom(String recherche) {
        TypedQuery<Membre> query = entityManager.createQuery(
            "SELECT m FROM Membre m WHERE LOWER(m.nom) LIKE LOWER(:recherche) OR LOWER(m.prenom) LIKE LOWER(:recherche)",
            Membre.class);
        query.setParameter("recherche", "%" + recherche + "%");
        return query.getResultList();
    }

    /** Trouve tous les membres actifs avec pagination et tri */
    public List<Membre> findAllActifs(Page page, Sort sort) {
        String orderBy = sort != null ? " ORDER BY " + buildOrderBy(sort) : "";
        TypedQuery<Membre> query = entityManager.createQuery(
            "SELECT m FROM Membre m WHERE m.actif = true" + orderBy, Membre.class);
        query.setFirstResult(page.index * page.size);
        query.setMaxResults(page.size);
        return query.getResultList();
    }

    /** Trouve les membres par nom ou prénom avec pagination et tri */
    public List<Membre> findByNomOrPrenom(String recherche, Page page, Sort sort) {
        String orderBy = sort != null ? " ORDER BY " + buildOrderBy(sort) : "";
        TypedQuery<Membre> query = entityManager.createQuery(
            "SELECT m FROM Membre m WHERE LOWER(m.nom) LIKE LOWER(:recherche) OR LOWER(m.prenom) LIKE LOWER(:recherche)" + orderBy,
            Membre.class);
        query.setParameter("recherche", "%" + recherche + "%");
        query.setFirstResult(page.index * page.size);
        query.setMaxResults(page.size);
        return query.getResultList();
    }

    /** Compte les nouveaux membres depuis une date donnée */
    public long countNouveauxMembres(LocalDate depuis) {
        TypedQuery<Long> query = entityManager.createQuery(
            "SELECT COUNT(m) FROM Membre m WHERE m.dateAdhesion >= :depuis", Long.class);
        query.setParameter("depuis", depuis);
        return query.getSingleResult();
    }

    /** Trouve les membres par statut avec pagination */
    public List<Membre> findByStatut(boolean actif, Page page, Sort sort) {
        String orderBy = sort != null ? " ORDER BY " + buildOrderBy(sort) : "";
        TypedQuery<Membre> query = entityManager.createQuery(
            "SELECT m FROM Membre m WHERE m.actif = :actif" + orderBy, Membre.class);
        query.setParameter("actif", actif);
        query.setFirstResult(page.index * page.size);
        query.setMaxResults(page.size);
        return query.getResultList();
    }

    /** Trouve les membres par tranche d'âge */
    public List<Membre> findByTrancheAge(int ageMin, int ageMax, Page page, Sort sort) {
        LocalDate dateNaissanceMax = LocalDate.now().minusYears(ageMin);
        LocalDate dateNaissanceMin = LocalDate.now().minusYears(ageMax + 1);
        String orderBy = sort != null ? " ORDER BY " + buildOrderBy(sort) : "";
        TypedQuery<Membre> query = entityManager.createQuery(
            "SELECT m FROM Membre m WHERE m.dateNaissance BETWEEN :dateMin AND :dateMax" + orderBy,
            Membre.class);
        query.setParameter("dateMin", dateNaissanceMin);
        query.setParameter("dateMax", dateNaissanceMax);
        query.setFirstResult(page.index * page.size);
        query.setMaxResults(page.size);
        return query.getResultList();
    }

    /** Recherche avancée de membres */
    public List<Membre> rechercheAvancee(
        String recherche,
        Boolean actif,
        LocalDate dateAdhesionMin,
        LocalDate dateAdhesionMax,
        Page page,
        Sort sort) {
        StringBuilder jpql = new StringBuilder("SELECT m FROM Membre m WHERE 1=1");
        
        if (recherche != null && !recherche.isEmpty()) {
            jpql.append(" AND (LOWER(m.nom) LIKE LOWER(:recherche) OR LOWER(m.prenom) LIKE LOWER(:recherche) OR LOWER(m.email) LIKE LOWER(:recherche))");
        }
        if (actif != null) {
            jpql.append(" AND m.actif = :actif");
        }
        if (dateAdhesionMin != null) {
            jpql.append(" AND m.dateAdhesion >= :dateAdhesionMin");
        }
        if (dateAdhesionMax != null) {
            jpql.append(" AND m.dateAdhesion <= :dateAdhesionMax");
        }
        
        if (sort != null) {
            jpql.append(" ORDER BY ").append(buildOrderBy(sort));
        }
        
        TypedQuery<Membre> query = entityManager.createQuery(jpql.toString(), Membre.class);
        
        if (recherche != null && !recherche.isEmpty()) {
            query.setParameter("recherche", "%" + recherche + "%");
        }
        if (actif != null) {
            query.setParameter("actif", actif);
        }
        if (dateAdhesionMin != null) {
            query.setParameter("dateAdhesionMin", dateAdhesionMin);
        }
        if (dateAdhesionMax != null) {
            query.setParameter("dateAdhesionMax", dateAdhesionMax);
        }
        
        query.setFirstResult(page.index * page.size);
        query.setMaxResults(page.size);
        return query.getResultList();
    }

    /** Construit la clause ORDER BY à partir d'un Sort */
    private String buildOrderBy(Sort sort) {
        if (sort == null || sort.getColumns().isEmpty()) {
            return "m.id";
        }
        StringBuilder orderBy = new StringBuilder();
        for (int i = 0; i < sort.getColumns().size(); i++) {
            if (i > 0) {
                orderBy.append(", ");
            }
            Sort.Column column = sort.getColumns().get(i);
            orderBy.append("m.").append(column.getName());
            if (column.getDirection() == Sort.Direction.Descending) {
                orderBy.append(" DESC");
            } else {
                orderBy.append(" ASC");
            }
        }
        return orderBy.toString();
    }

    /**
     * Compte les membres actifs dans une période et organisation
     *
     * @param organisationId UUID de l'organisation
     * @param debut Date de début
     * @param fin Date de fin
     * @return Nombre de membres actifs
     */
    public Long countMembresActifs(UUID organisationId, LocalDateTime debut, LocalDateTime fin) {
        TypedQuery<Long> query = entityManager.createQuery(
            "SELECT COUNT(m) FROM Membre m WHERE m.organisation.id = :organisationId AND m.actif = true AND m.dateAdhesion BETWEEN :debut AND :fin",
            Long.class);
        query.setParameter("organisationId", organisationId);
        query.setParameter("debut", debut);
        query.setParameter("fin", fin);
        return query.getSingleResult();
    }

    /**
     * Compte les membres inactifs dans une période et organisation
     *
     * @param organisationId UUID de l'organisation
     * @param debut Date de début
     * @param fin Date de fin
     * @return Nombre de membres inactifs
     */
    public Long countMembresInactifs(UUID organisationId, LocalDateTime debut, LocalDateTime fin) {
        TypedQuery<Long> query = entityManager.createQuery(
            "SELECT COUNT(m) FROM Membre m WHERE m.organisation.id = :organisationId AND m.actif = false AND m.dateAdhesion BETWEEN :debut AND :fin",
            Long.class);
        query.setParameter("organisationId", organisationId);
        query.setParameter("debut", debut);
        query.setParameter("fin", fin);
        return query.getSingleResult();
    }

    /**
     * Calcule la moyenne d'âge des membres dans une période et organisation
     *
     * @param organisationId UUID de l'organisation
     * @param debut Date de début
     * @param fin Date de fin
     * @return Moyenne d'âge ou null si aucun membre
     */
    public Double calculerMoyenneAge(UUID organisationId, LocalDateTime debut, LocalDateTime fin) {
        TypedQuery<Double> query = entityManager.createQuery(
            "SELECT AVG(YEAR(CURRENT_DATE) - YEAR(m.dateNaissance)) FROM Membre m WHERE m.organisation.id = :organisationId AND m.dateAdhesion BETWEEN :debut AND :fin",
            Double.class);
        query.setParameter("organisationId", organisationId);
        query.setParameter("debut", debut);
        query.setParameter("fin", fin);
        return query.getSingleResult();
    }
}
