package dev.lions.unionflow.server.service.collectefonds;

import dev.lions.unionflow.server.api.dto.collectefonds.CampagneCollecteResponse;
import dev.lions.unionflow.server.api.dto.collectefonds.ContributionCollecteDTO;
import dev.lions.unionflow.server.api.enums.collectefonds.StatutCampagneCollecte;
import dev.lions.unionflow.server.api.enums.wave.StatutTransactionWave;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.collectefonds.CampagneCollecte;
import dev.lions.unionflow.server.entity.collectefonds.ContributionCollecte;
import dev.lions.unionflow.server.mapper.collectefonds.CampagneCollecteMapper;
import dev.lions.unionflow.server.mapper.collectefonds.ContributionCollecteMapper;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.collectefonds.CampagneCollecteRepository;
import dev.lions.unionflow.server.repository.collectefonds.ContributionCollecteRepository;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.NotFoundException;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@ApplicationScoped
public class CampagneCollecteService {

    @Inject
    CampagneCollecteRepository campagneCollecteRepository;

    @Inject
    ContributionCollecteRepository contributionCollecteRepository;

    @Inject
    OrganisationRepository organisationRepository;

    @Inject
    MembreRepository membreRepository;

    @Inject
    CampagneCollecteMapper campagneCollecteMapper;

    @Inject
    ContributionCollecteMapper contributionCollecteMapper;

    public CampagneCollecteResponse getCampagneById(UUID id) {
        CampagneCollecte campagne = campagneCollecteRepository.findByIdOptional(id)
                .orElseThrow(() -> new NotFoundException("Campagne de collecte non trouvée avec l'ID: " + id));
        return campagneCollecteMapper.toDto(campagne);
    }

    public List<CampagneCollecteResponse> getCampagnesByOrganisation(UUID organisationId) {
        return campagneCollecteRepository.find("organisation.id = ?1 and actif = true", organisationId)
                .stream()
                .map(campagneCollecteMapper::toDto)
                .collect(Collectors.toList());
    }

    @Transactional
    public ContributionCollecteDTO contribuer(UUID campagneId, ContributionCollecteDTO dto) {
        CampagneCollecte campagne = campagneCollecteRepository.findByIdOptional(campagneId)
                .orElseThrow(() -> new NotFoundException("Campagne de collecte non trouvée avec l'ID: " + campagneId));

        if (campagne.getStatut() != StatutCampagneCollecte.EN_COURS) {
            throw new IllegalStateException("La campagne n'est plus ouverte aux contributions.");
        }

        ContributionCollecte contribution = contributionCollecteMapper.toEntity(dto);
        contribution.setCampagne(campagne);

        if (dto.getMembreDonateurId() != null) {
            Membre membre = membreRepository.findByIdOptional(UUID.fromString(dto.getMembreDonateurId()))
                    .orElseThrow(
                            () -> new NotFoundException("Membre non trouvé avec l'ID: " + dto.getMembreDonateurId()));
            contribution.setMembreDonateur(membre);
        }

        contribution.setDateContribution(LocalDateTime.now());
        contribution.setStatutPaiement(StatutTransactionWave.REUSSIE); // Simplification pour le moment

        contributionCollecteRepository.persist(contribution);

        // Mise à jour des compteurs de la campagne
        campagne.setMontantCollecteActuel(campagne.getMontantCollecteActuel().add(contribution.getMontantSoutien()));
        campagne.setNombreDonateurs(campagne.getNombreDonateurs() + 1);

        return contributionCollecteMapper.toDto(contribution);
    }
}
