package dev.lions.unionflow.server.repository;

import dev.lions.unionflow.server.entity.Membre;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import io.quarkus.panache.common.Page;
import io.quarkus.panache.common.Sort;
import jakarta.enterprise.context.ApplicationScoped;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

/**
 * Repository pour l'entité Membre
 */
@ApplicationScoped
public class MembreRepository implements PanacheRepository<Membre> {

    /**
     * Trouve un membre par son email
     */
    public Optional<Membre> findByEmail(String email) {
        return find("email", email).firstResultOptional();
    }

    /**
     * Trouve un membre par son numéro
     */
    public Optional<Membre> findByNumeroMembre(String numeroMembre) {
        return find("numeroMembre", numeroMembre).firstResultOptional();
    }

    /**
     * Trouve tous les membres actifs
     */
    public List<Membre> findAllActifs() {
        return find("actif", true).list();
    }

    /**
     * Compte le nombre de membres actifs
     */
    public long countActifs() {
        return count("actif", true);
    }

    /**
     * Trouve les membres par nom ou prénom (recherche partielle)
     */
    public List<Membre> findByNomOrPrenom(String recherche) {
        return find("lower(nom) like ?1 or lower(prenom) like ?1",
                   "%" + recherche.toLowerCase() + "%").list();
    }

    /**
     * Trouve tous les membres actifs avec pagination et tri
     */
    public List<Membre> findAllActifs(Page page, Sort sort) {
        return find("actif", sort, true).page(page).list();
    }

    /**
     * Trouve les membres par nom ou prénom avec pagination et tri
     */
    public List<Membre> findByNomOrPrenom(String recherche, Page page, Sort sort) {
        return find("lower(nom) like ?1 or lower(prenom) like ?1",
                   sort, "%" + recherche.toLowerCase() + "%")
                   .page(page).list();
    }

    /**
     * Compte les nouveaux membres depuis une date donnée
     */
    public long countNouveauxMembres(LocalDate depuis) {
        return count("dateAdhesion >= ?1", depuis);
    }

    /**
     * Trouve les membres par statut avec pagination
     */
    public List<Membre> findByStatut(boolean actif, Page page, Sort sort) {
        return find("actif", sort, actif).page(page).list();
    }

    /**
     * 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);

        return find("dateNaissance between ?1 and ?2", sort, dateNaissanceMin, dateNaissanceMax)
                .page(page).list();
    }

    /**
     * Recherche avancée avec filtres multiples
     */
    public List<Membre> rechercheAvancee(String recherche, Boolean actif,
                                       LocalDate dateAdhesionMin, LocalDate dateAdhesionMax,
                                       Page page, Sort sort) {
        StringBuilder query = new StringBuilder("1=1");
        java.util.Map<String, Object> params = new java.util.HashMap<>();

        if (recherche != null && !recherche.trim().isEmpty()) {
            query.append(" and (lower(nom) like :recherche or lower(prenom) like :recherche or lower(email) like :recherche)");
            params.put("recherche", "%" + recherche.toLowerCase() + "%");
        }

        if (actif != null) {
            query.append(" and actif = :actif");
            params.put("actif", actif);
        }

        if (dateAdhesionMin != null) {
            query.append(" and dateAdhesion >= :dateAdhesionMin");
            params.put("dateAdhesionMin", dateAdhesionMin);
        }

        if (dateAdhesionMax != null) {
            query.append(" and dateAdhesion <= :dateAdhesionMax");
            params.put("dateAdhesionMax", dateAdhesionMax);
        }

        return find(query.toString(), sort, params).page(page).list();
    }

    /**
     * Compte les membres actifs dans une période et organisation
     */
    public long countMembresActifs(java.util.UUID organisationId, java.time.LocalDateTime debut, java.time.LocalDateTime fin) {
        return count("organisation.id = ?1 and actif = true and dateAdhesion between ?2 and ?3",
                    organisationId, debut, fin);
    }

    /**
     * Compte les membres inactifs dans une période et organisation
     */
    public long countMembresInactifs(java.util.UUID organisationId, java.time.LocalDateTime debut, java.time.LocalDateTime fin) {
        return count("organisation.id = ?1 and actif = false and dateAdhesion between ?2 and ?3",
                    organisationId, debut, fin);
    }

    /**
     * Calcule la moyenne d'âge des membres dans une période et organisation
     */
    public Double calculerMoyenneAge(java.util.UUID organisationId, java.time.LocalDateTime debut, java.time.LocalDateTime fin) {
        return find("SELECT AVG(YEAR(CURRENT_DATE) - YEAR(m.dateNaissance)) FROM Membre m WHERE m.organisation.id = ?1 and m.dateAdhesion between ?2 and ?3",
                   organisationId, debut, fin)
               .project(Double.class)
               .firstResult();
    }
}
