package dev.lions.unionflow.server.repository;

import dev.lions.unionflow.server.entity.TransactionApproval;
import io.quarkus.arc.Unremovable;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.persistence.TypedQuery;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
 * Repository pour la gestion des approbations de transactions
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-03-13
 */
@ApplicationScoped
@Unremovable
public class TransactionApprovalRepository extends BaseRepository<TransactionApproval> {

    public TransactionApprovalRepository() {
        super(TransactionApproval.class);
    }

    /**
     * Trouve toutes les approbations en attente
     *
     * @return Liste des approbations en attente
     */
    public List<TransactionApproval> findPending() {
        return entityManager.createQuery(
                "SELECT a FROM TransactionApproval a WHERE a.status = 'PENDING' ORDER BY a.createdAt DESC",
                TransactionApproval.class)
            .getResultList();
    }

    /**
     * Trouve les approbations en attente pour une organisation
     *
     * @param organisationId ID de l'organisation
     * @return Liste des approbations en attente
     */
    public List<TransactionApproval> findPendingByOrganisation(UUID organisationId) {
        return entityManager.createQuery(
                "SELECT a FROM TransactionApproval a " +
                "WHERE a.status = 'PENDING' AND a.organisation.id = :orgId " +
                "ORDER BY a.createdAt DESC",
                TransactionApproval.class)
            .setParameter("orgId", organisationId)
            .getResultList();
    }

    /**
     * Trouve une approbation par ID de transaction
     *
     * @param transactionId ID de la transaction
     * @return Optional contenant l'approbation si trouvée
     */
    public Optional<TransactionApproval> findByTransactionId(UUID transactionId) {
        return entityManager.createQuery(
                "SELECT a FROM TransactionApproval a WHERE a.transactionId = :txId",
                TransactionApproval.class)
            .setParameter("txId", transactionId)
            .getResultList()
            .stream()
            .findFirst();
    }

    /**
     * Trouve les approbations expirées non traitées
     *
     * @return Liste des approbations expirées
     */
    public List<TransactionApproval> findExpired() {
        return entityManager.createQuery(
                "SELECT a FROM TransactionApproval a " +
                "WHERE a.status = 'PENDING' AND a.expiresAt < :now",
                TransactionApproval.class)
            .setParameter("now", LocalDateTime.now())
            .getResultList();
    }

    /**
     * Trouve l'historique des approbations pour une organisation
     *
     * @param organisationId ID de l'organisation
     * @param startDate Date de début (optionnel)
     * @param endDate Date de fin (optionnel)
     * @param status Statut (optionnel)
     * @return Liste des approbations
     */
    public List<TransactionApproval> findHistory(
            UUID organisationId,
            LocalDateTime startDate,
            LocalDateTime endDate,
            String status) {

        StringBuilder jpql = new StringBuilder(
            "SELECT a FROM TransactionApproval a WHERE a.organisation.id = :orgId");

        if (startDate != null) {
            jpql.append(" AND a.createdAt >= :startDate");
        }
        if (endDate != null) {
            jpql.append(" AND a.createdAt <= :endDate");
        }
        if (status != null && !status.isEmpty()) {
            jpql.append(" AND a.status = :status");
        }

        jpql.append(" ORDER BY a.createdAt DESC");

        TypedQuery<TransactionApproval> query = entityManager.createQuery(jpql.toString(), TransactionApproval.class);
        query.setParameter("orgId", organisationId);

        if (startDate != null) {
            query.setParameter("startDate", startDate);
        }
        if (endDate != null) {
            query.setParameter("endDate", endDate);
        }
        if (status != null && !status.isEmpty()) {
            query.setParameter("status", status);
        }

        return query.getResultList();
    }

    /**
     * Compte les approbations en attente pour une organisation
     *
     * @param organisationId ID de l'organisation
     * @return Nombre d'approbations en attente
     */
    public long countPendingByOrganisation(UUID organisationId) {
        return entityManager.createQuery(
                "SELECT COUNT(a) FROM TransactionApproval a " +
                "WHERE a.status = 'PENDING' AND a.organisation.id = :orgId",
                Long.class)
            .setParameter("orgId", organisationId)
            .getSingleResult();
    }
}
