package dev.lions.unionflow.server.repository;

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.panache.common.Page;
import io.quarkus.panache.common.Sort;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.persistence.TypedQuery;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

/** Repository pour les demandes d'aide avec UUID */
@ApplicationScoped
public class DemandeAideRepository extends BaseRepository<DemandeAide> {

    public DemandeAideRepository() {
        super(DemandeAide.class);
    }

    /** Trouve toutes les demandes d'aide par organisation */
    public List<DemandeAide> findByOrganisationId(UUID organisationId) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.organisation.id = :organisationId",
                DemandeAide.class);
        query.setParameter("organisationId", organisationId);
        return query.getResultList();
    }

    /** Trouve toutes les demandes d'aide par organisation avec pagination */
    public List<DemandeAide> findByOrganisationId(UUID organisationId, Page page, Sort sort) {
        String orderBy = sort != null ? " ORDER BY " + buildOrderBy(sort) : " ORDER BY d.dateDemande DESC";
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.organisation.id = :organisationId" + orderBy,
                DemandeAide.class);
        query.setParameter("organisationId", organisationId);
        query.setFirstResult(page.index * page.size);
        query.setMaxResults(page.size);
        return query.getResultList();
    }

    /** Trouve toutes les demandes d'aide par demandeur */
    public List<DemandeAide> findByDemandeurId(UUID demandeurId) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.demandeur.id = :demandeurId",
                DemandeAide.class);
        query.setParameter("demandeurId", demandeurId);
        return query.getResultList();
    }

    /** Trouve toutes les demandes d'aide par statut */
    public List<DemandeAide> findByStatut(StatutAide statut) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.statut = :statut",
                DemandeAide.class);
        query.setParameter("statut", statut);
        return query.getResultList();
    }

    /** Trouve toutes les demandes d'aide par statut et organisation */
    public List<DemandeAide> findByStatutAndOrganisationId(StatutAide statut, UUID organisationId) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.statut = :statut AND d.organisation.id = :organisationId",
                DemandeAide.class);
        query.setParameter("statut", statut);
        query.setParameter("organisationId", organisationId);
        return query.getResultList();
    }

    /** Trouve toutes les demandes d'aide par type */
    public List<DemandeAide> findByTypeAide(TypeAide typeAide) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.typeAide = :typeAide",
                DemandeAide.class);
        query.setParameter("typeAide", typeAide);
        return query.getResultList();
    }

    /** Trouve toutes les demandes d'aide urgentes */
    public List<DemandeAide> findUrgentes() {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.urgence = true",
                DemandeAide.class);
        return query.getResultList();
    }

    /** Trouve toutes les demandes d'aide urgentes par organisation */
    public List<DemandeAide> findUrgentesByOrganisationId(UUID organisationId) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.urgence = true AND d.organisation.id = :organisationId",
                DemandeAide.class);
        query.setParameter("organisationId", organisationId);
        return query.getResultList();
    }

    /** Trouve toutes les demandes d'aide dans une période */
    public List<DemandeAide> findByPeriode(LocalDateTime debut, LocalDateTime fin) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.dateDemande >= :debut AND d.dateDemande <= :fin",
                DemandeAide.class);
        query.setParameter("debut", debut);
        query.setParameter("fin", fin);
        return query.getResultList();
    }

    /** Trouve toutes les demandes d'aide dans une période pour une organisation */
    public List<DemandeAide> findByPeriodeAndOrganisationId(
            LocalDateTime debut, LocalDateTime fin, UUID organisationId) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.dateDemande >= :debut AND d.dateDemande <= :fin AND d.organisation.id = :organisationId",
                DemandeAide.class);
        query.setParameter("debut", debut);
        query.setParameter("fin", fin);
        query.setParameter("organisationId", organisationId);
        return query.getResultList();
    }

    /** Compte le nombre de demandes par statut */
    public long countByStatut(String statut) {
        TypedQuery<Long> query = entityManager.createQuery(
                "SELECT COUNT(d) FROM DemandeAide d WHERE d.statut = :statut",
                Long.class);
        query.setParameter("statut", StatutAide.valueOf(statut));
        return query.getSingleResult();
    }

    /** Compte le nombre de demandes par statut et organisation */
    public long countByStatutAndOrganisationId(String statut, UUID organisationId) {
        TypedQuery<Long> query = entityManager.createQuery(
                "SELECT COUNT(d) FROM DemandeAide d WHERE d.statut = :statut AND d.organisation.id = :organisationId",
                Long.class);
        query.setParameter("statut", StatutAide.valueOf(statut));
        query.setParameter("organisationId", organisationId);
        return query.getSingleResult();
    }

    /** Calcule le montant total demandé par organisation */
    public Optional<BigDecimal> sumMontantDemandeByOrganisationId(UUID organisationId) {
        TypedQuery<BigDecimal> query = entityManager.createQuery(
                "SELECT COALESCE(SUM(d.montantDemande), 0) FROM DemandeAide d WHERE d.organisation.id = :organisationId",
                BigDecimal.class);
        query.setParameter("organisationId", organisationId);
        BigDecimal result = query.getSingleResult();
        return result != null && result.compareTo(BigDecimal.ZERO) > 0
                ? Optional.of(result)
                : Optional.empty();
    }

    /** Calcule le montant total approuvé par organisation */
    public Optional<BigDecimal> sumMontantApprouveByOrganisationId(UUID organisationId) {
        TypedQuery<BigDecimal> query = entityManager.createQuery(
                "SELECT COALESCE(SUM(d.montantApprouve), 0) FROM DemandeAide d WHERE d.organisation.id = :organisationId AND d.statut = :statut",
                BigDecimal.class);
        query.setParameter("organisationId", organisationId);
        query.setParameter("statut", StatutAide.APPROUVEE);
        BigDecimal result = query.getSingleResult();
        return result != null && result.compareTo(BigDecimal.ZERO) > 0
                ? Optional.of(result)
                : Optional.empty();
    }

    /** Trouve les demandes d'aide récentes (dernières 30 jours) */
    public List<DemandeAide> findRecentes() {
        LocalDateTime il30Jours = LocalDateTime.now().minusDays(30);
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.dateDemande >= :il30Jours ORDER BY d.dateDemande DESC",
                DemandeAide.class);
        query.setParameter("il30Jours", il30Jours);
        return query.getResultList();
    }

    /** Trouve les demandes d'aide récentes par organisation */
    public List<DemandeAide> findRecentesByOrganisationId(UUID organisationId) {
        LocalDateTime il30Jours = LocalDateTime.now().minusDays(30);
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.dateDemande >= :il30Jours AND d.organisation.id = :organisationId ORDER BY d.dateDemande DESC",
                DemandeAide.class);
        query.setParameter("il30Jours", il30Jours);
        query.setParameter("organisationId", organisationId);
        return query.getResultList();
    }

    /** Trouve les demandes d'aide en attente depuis plus de X jours */
    public List<DemandeAide> findEnAttenteDepuis(int nombreJours) {
        LocalDateTime dateLimit = LocalDateTime.now().minusDays(nombreJours);
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.statut = :statut AND d.dateDemande <= :dateLimit",
                DemandeAide.class);
        query.setParameter("statut", StatutAide.EN_ATTENTE);
        query.setParameter("dateLimit", dateLimit);
        return query.getResultList();
    }

    /** Trouve les demandes d'aide par évaluateur */
    public List<DemandeAide> findByEvaluateurId(UUID evaluateurId) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.evaluateur.id = :evaluateurId",
                DemandeAide.class);
        query.setParameter("evaluateurId", evaluateurId);
        return query.getResultList();
    }

    /** Trouve les demandes d'aide en cours d'évaluation par évaluateur */
    public List<DemandeAide> findEnCoursEvaluationByEvaluateurId(UUID evaluateurId) {
        TypedQuery<DemandeAide> query = entityManager.createQuery(
                "SELECT d FROM DemandeAide d WHERE d.evaluateur.id = :evaluateurId AND d.statut = :statut",
                DemandeAide.class);
        query.setParameter("evaluateurId", evaluateurId);
        query.setParameter("statut", StatutAide.EN_COURS_EVALUATION);
        return query.getResultList();
    }

    /** Compte les demandes approuvées dans une période */
    public long countDemandesApprouvees(UUID organisationId, LocalDateTime debut, LocalDateTime fin) {
        TypedQuery<Long> query = entityManager.createQuery(
                "SELECT COUNT(d) FROM DemandeAide d WHERE d.organisation.id = :organisationId AND d.statut = :statut AND d.dateCreation BETWEEN :debut AND :fin",
                Long.class);
        query.setParameter("organisationId", organisationId);
        query.setParameter("statut", StatutAide.APPROUVEE);
        query.setParameter("debut", debut);
        query.setParameter("fin", fin);
        return query.getSingleResult();
    }

    /** Compte toutes les demandes dans une période */
    public long countDemandes(UUID organisationId, LocalDateTime debut, LocalDateTime fin) {
        TypedQuery<Long> query = entityManager.createQuery(
                "SELECT COUNT(d) FROM DemandeAide d WHERE d.organisation.id = :organisationId AND d.dateCreation BETWEEN :debut AND :fin",
                Long.class);
        query.setParameter("organisationId", organisationId);
        query.setParameter("debut", debut);
        query.setParameter("fin", fin);
        return query.getSingleResult();
    }

    /** Somme des montants accordés dans une période */
    public BigDecimal sumMontantsAccordes(
            UUID organisationId, LocalDateTime debut, LocalDateTime fin) {
        TypedQuery<BigDecimal> query = entityManager.createQuery(
                "SELECT COALESCE(SUM(d.montantApprouve), 0) FROM DemandeAide d WHERE d.organisation.id = :organisationId AND d.statut = :statut AND d.dateCreation BETWEEN :debut AND :fin",
                BigDecimal.class);
        query.setParameter("organisationId", organisationId);
        query.setParameter("statut", StatutAide.APPROUVEE);
        query.setParameter("debut", debut);
        query.setParameter("fin", fin);
        return query.getSingleResult();
    }

    /** Construit la clause ORDER BY à partir d'un Sort */
    private String buildOrderBy(Sort sort) {
        if (sort.getColumns().isEmpty()) {
            return "d.dateDemande DESC";
        }
        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("d.").append(column.getName());
            if (column.getDirection() == Sort.Direction.Descending) {
                orderBy.append(" DESC");
            } else {
                orderBy.append(" ASC");
            }
        }
        return orderBy.toString();
    }
}
