package dev.lions.unionflow.server.repository;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import dev.lions.unionflow.server.entity.DemandeAide;
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
import io.quarkus.panache.common.Page;
import io.quarkus.panache.common.Sort;
import jakarta.enterprise.context.ApplicationScoped;

/**
 * Repository pour les demandes d'aide
 */
@ApplicationScoped
public class DemandeAideRepository implements PanacheRepositoryBase<DemandeAide, UUID> {

    /**
     * Trouve toutes les demandes d'aide par organisation
     */
    public List<DemandeAide> findByOrganisationId(UUID organisationId) {
        return find("organisation.id", organisationId).list();
    }

    /**
     * Trouve toutes les demandes d'aide par organisation avec pagination
     */
    public List<DemandeAide> findByOrganisationId(UUID organisationId, Page page, Sort sort) {
        return find("organisation.id = ?1 ORDER BY dateDemande DESC", organisationId)
                .page(page).list();
    }

    /**
     * Trouve toutes les demandes d'aide par demandeur
     */
    public List<DemandeAide> findByDemandeurId(UUID demandeurId) {
        return find("demandeur.id", demandeurId).list();
    }

    /**
     * Trouve toutes les demandes d'aide par statut
     */
    public List<DemandeAide> findByStatut(StatutAide statut) {
        return find("statut", statut).list();
    }

    /**
     * Trouve toutes les demandes d'aide par statut et organisation
     */
    public List<DemandeAide> findByStatutAndOrganisationId(StatutAide statut, UUID organisationId) {
        return find("statut = ?1 and organisation.id = ?2", statut, organisationId).list();
    }

    /**
     * Trouve toutes les demandes d'aide par type
     */
    public List<DemandeAide> findByTypeAide(TypeAide typeAide) {
        return find("typeAide", typeAide).list();
    }

    /**
     * Trouve toutes les demandes d'aide urgentes
     */
    public List<DemandeAide> findUrgentes() {
        return find("urgence", true).list();
    }

    /**
     * Trouve toutes les demandes d'aide urgentes par organisation
     */
    public List<DemandeAide> findUrgentesByOrganisationId(UUID organisationId) {
        return find("urgence = true and organisation.id = ?1", organisationId).list();
    }

    /**
     * Trouve toutes les demandes d'aide dans une période
     */
    public List<DemandeAide> findByPeriode(LocalDateTime debut, LocalDateTime fin) {
        return find("dateDemande >= ?1 and dateDemande <= ?2", debut, fin).list();
    }

    /**
     * Trouve toutes les demandes d'aide dans une période pour une organisation
     */
    public List<DemandeAide> findByPeriodeAndOrganisationId(LocalDateTime debut, LocalDateTime fin, UUID organisationId) {
        return find("dateDemande >= ?1 and dateDemande <= ?2 and organisation.id = ?3", debut, fin, organisationId).list();
    }

    /**
     * Compte le nombre de demandes par statut
     */
    public long countByStatut(StatutAide statut) {
        return count("statut", statut);
    }

    /**
     * Compte le nombre de demandes par statut et organisation
     */
    public long countByStatutAndOrganisationId(StatutAide statut, UUID organisationId) {
        return count("statut = ?1 and organisation.id = ?2", statut, organisationId);
    }

    /**
     * Calcule le montant total demandé par organisation
     */
    public Optional<BigDecimal> sumMontantDemandeByOrganisationId(UUID organisationId) {
        return find("SELECT SUM(d.montantDemande) FROM DemandeAide d WHERE d.organisation.id = ?1", organisationId)
                .project(BigDecimal.class)
                .firstResultOptional();
    }

    /**
     * Calcule le montant total approuvé par organisation
     */
    public Optional<BigDecimal> sumMontantApprouveByOrganisationId(UUID organisationId) {
        return find("SELECT SUM(d.montantApprouve) FROM DemandeAide d WHERE d.organisation.id = ?1 AND d.statut = ?2", 
                organisationId, StatutAide.APPROUVEE)
                .project(BigDecimal.class)
                .firstResultOptional();
    }

    /**
     * Trouve les demandes d'aide récentes (dernières 30 jours)
     */
    public List<DemandeAide> findRecentes() {
        LocalDateTime il30Jours = LocalDateTime.now().minusDays(30);
        return find("dateDemande >= ?1", Sort.by("dateDemande").descending(), il30Jours).list();
    }

    /**
     * Trouve les demandes d'aide récentes par organisation
     */
    public List<DemandeAide> findRecentesByOrganisationId(UUID organisationId) {
        LocalDateTime il30Jours = LocalDateTime.now().minusDays(30);
        return find("dateDemande >= ?1 and organisation.id = ?2", Sort.by("dateDemande").descending(), 
                il30Jours, organisationId).list();
    }

    /**
     * Trouve les demandes d'aide en attente depuis plus de X jours
     */
    public List<DemandeAide> findEnAttenteDepuis(int nombreJours) {
        LocalDateTime dateLimit = LocalDateTime.now().minusDays(nombreJours);
        return find("statut = ?1 and dateDemande <= ?2", StatutAide.EN_ATTENTE, dateLimit).list();
    }

    /**
     * Trouve les demandes d'aide par évaluateur
     */
    public List<DemandeAide> findByEvaluateurId(UUID evaluateurId) {
        return find("evaluateur.id", evaluateurId).list();
    }

    /**
     * Trouve les demandes d'aide en cours d'évaluation par évaluateur
     */
    public List<DemandeAide> findEnCoursEvaluationByEvaluateurId(UUID evaluateurId) {
        return find("evaluateur.id = ?1 and statut = ?2", evaluateurId, StatutAide.EN_COURS_EVALUATION).list();
    }

    /**
     * Compte les demandes approuvées dans une période
     */
    public long countDemandesApprouvees(UUID organisationId, LocalDateTime debut, LocalDateTime fin) {
        return count("organisation.id = ?1 and statut = ?2 and dateCreation between ?3 and ?4",
                    organisationId, StatutAide.APPROUVEE, debut, fin);
    }

    /**
     * Compte toutes les demandes dans une période
     */
    public long countDemandes(UUID organisationId, LocalDateTime debut, LocalDateTime fin) {
        return count("organisation.id = ?1 and dateCreation between ?2 and ?3",
                    organisationId, debut, fin);
    }

    /**
     * Somme des montants accordés dans une période
     */
    public BigDecimal sumMontantsAccordes(UUID organisationId, LocalDateTime debut, LocalDateTime fin) {
        return find("SELECT COALESCE(SUM(d.montantAccorde), 0) FROM DemandeAide d WHERE d.organisation.id = ?1 and d.statut = ?2 and d.dateCreation between ?3 and ?4",
                   organisationId, StatutAide.APPROUVEE, debut, fin)
               .project(BigDecimal.class)
               .firstResult();
    }
}
