package br.gov.sigefp.treasury.service;

import br.gov.sigefp.treasury.api.dto.CreatePaymentBatchDTO;
import br.gov.sigefp.treasury.api.dto.PaymentBatchDTO;
import br.gov.sigefp.treasury.domain.PaymentBatch;
import br.gov.sigefp.treasury.repository.PaymentBatchRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * Serviço de aplicação para gestão de lotes de pagamento.
 */
@Service
@RequiredArgsConstructor
@Transactional
public class PaymentBatchService {

    private final PaymentBatchRepository paymentBatchRepository;

    public PaymentBatchDTO create(CreatePaymentBatchDTO dto) {
        PaymentBatch paymentBatch = PaymentBatch.builder()
                .periodId(dto.getPeriodId())
                .ministryId(dto.getMinistryId())
                .status("CREATED")
                .build();

        PaymentBatch saved = paymentBatchRepository.save(paymentBatch);
        return toDTO(saved);
    }

    public PaymentBatchDTO updateStatus(UUID id, String status) {
        PaymentBatch paymentBatch = paymentBatchRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Lote de pagamento não encontrado: " + id));

        paymentBatch.setStatus(status);
        PaymentBatch saved = paymentBatchRepository.save(paymentBatch);
        return toDTO(saved);
    }

    @Transactional(readOnly = true)
    public PaymentBatchDTO findById(UUID id) {
        PaymentBatch paymentBatch = paymentBatchRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Lote de pagamento não encontrado: " + id));
        return toDTO(paymentBatch);
    }

    @Transactional(readOnly = true)
    public Page<PaymentBatchDTO> findAll(Pageable pageable) {
        return paymentBatchRepository.findAll(pageable).map(this::toDTO);
    }

    @Transactional(readOnly = true)
    public List<PaymentBatchDTO> findByPeriodId(Long periodId) {
        return paymentBatchRepository.findByPeriodId(periodId).stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<PaymentBatchDTO> findByMinistryId(UUID ministryId) {
        return paymentBatchRepository.findByMinistryId(ministryId).stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<PaymentBatchDTO> findByStatus(String status) {
        return paymentBatchRepository.findByStatus(status).stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<PaymentBatchDTO> findByPeriodIdAndMinistryId(Long periodId, UUID ministryId) {
        return paymentBatchRepository.findByPeriodIdAndMinistryId(periodId, ministryId).stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<PaymentBatchDTO> findByPeriodIdAndStatus(Long periodId, String status) {
        return paymentBatchRepository.findByPeriodIdAndStatus(periodId, status).stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<PaymentBatchDTO> findByMinistryIdAndStatus(UUID ministryId, String status) {
        return paymentBatchRepository.findByMinistryIdAndStatus(ministryId, status).stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    private PaymentBatchDTO toDTO(PaymentBatch paymentBatch) {
        return PaymentBatchDTO.builder()
                .id(paymentBatch.getId())
                .periodId(paymentBatch.getPeriodId())
                .ministryId(paymentBatch.getMinistryId())
                .createdAt(paymentBatch.getCreatedAt())
                .createdBy(paymentBatch.getCreatedBy())
                .status(paymentBatch.getStatus())
                .build();
    }
}

