package br.gov.sigefp.treasury.integration;

import br.gov.sigefp.common.exception.BusinessException;
import br.gov.sigefp.common.exception.ResourceNotFoundException;
import br.gov.sigefp.treasury.domain.PaymentOrder;
import br.gov.sigefp.treasury.repository.PaymentOrderRepository;
import br.gov.sigefp.treasury.service.CashAccountService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.UUID;

/**
 * Serviço de integração do módulo Tesouro com outros módulos.
 * Similar a BudgetIntegrationService no módulo de Orçamento.
 */
@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class TreasuryIntegrationService {

    private final PaymentOrderRepository paymentOrderRepository;
    private final CashAccountService cashAccountService;

    /**
     * Valida se uma ordem de pagamento pode ser criada.
     * Verifica disponibilidade de caixa e integridade dos dados.
     */
    public void validatePaymentOrder(UUID paymentOrderId) {
        PaymentOrder paymentOrder = paymentOrderRepository.findById(paymentOrderId)
                .orElseThrow(() -> new ResourceNotFoundException(
                    "Ordem de pagamento não encontrada: " + paymentOrderId));

        // Validações básicas
        if (paymentOrder.getNetAmount() == null || paymentOrder.getNetAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException(
                "Valor líquido da ordem de pagamento deve ser maior que zero",
                "INVALID_AMOUNT",
                org.springframework.http.HttpStatus.BAD_REQUEST);
        }

        // Validação de disponibilidade de caixa será feita quando a ordem for programada
        // (requer cashAccountId na PaymentOrder, que pode ser adicionado no futuro)
        
        log.debug("Ordem de pagamento validada: paymentOrderId={}", paymentOrderId);
    }

    /**
     * Valida disponibilidade de caixa para um pagamento.
     */
    public void validateCashAvailability(UUID cashAccountId, BigDecimal amount) {
        if (cashAccountId == null) {
            throw new BusinessException(
                "Conta de caixa é obrigatória para validação",
                "MISSING_CASH_ACCOUNT",
                org.springframework.http.HttpStatus.BAD_REQUEST);
        }

        BigDecimal available = cashAccountService.getAvailableBalance(cashAccountId);
        
        if (amount.compareTo(available) > 0) {
            throw new BusinessException(
                String.format("Saldo disponível insuficiente. Disponível: %s, Solicitado: %s",
                    available, amount),
                "INSUFFICIENT_CASH",
                org.springframework.http.HttpStatus.CONFLICT);
        }

        log.debug("Disponibilidade de caixa validada: accountId={}, amount={}, available={}", 
                cashAccountId, amount, available);
    }

    /**
     * Registra a execução de um pagamento.
     * Atualiza saldos e cria entradas de tesouraria.
     */
    public void registerPaymentExecution(UUID paymentOrderId, BigDecimal amount, UUID cashAccountId) {
        PaymentOrder paymentOrder = paymentOrderRepository.findById(paymentOrderId)
                .orElseThrow(() -> new ResourceNotFoundException(
                    "Ordem de pagamento não encontrada: " + paymentOrderId));

        // Validar disponibilidade
        validateCashAvailability(cashAccountId, amount);

        // Atualizar saldo da conta
        cashAccountService.updateBalance(cashAccountId, amount, "OUTFLOW");

        log.info("Execução de pagamento registrada: paymentOrderId={}, amount={}, accountId={}", 
                paymentOrderId, amount, cashAccountId);
    }

    /**
     * Atualiza execução orçamentária após pagamento.
     * Este método será chamado pelo TreasuryPaymentService quando um pagamento for confirmado.
     */
    public void updateBudgetExecution(UUID paymentOrderId) {
        PaymentOrder paymentOrder = paymentOrderRepository.findById(paymentOrderId)
                .orElseThrow(() -> new ResourceNotFoundException(
                    "Ordem de pagamento não encontrada: " + paymentOrderId));

        // A atualização da execução orçamentária já é feita pelo TreasuryPaymentService
        // Este método pode ser usado para validações adicionais ou notificações
        
        log.debug("Execução orçamentária atualizada para ordem de pagamento: paymentOrderId={}", 
                paymentOrderId);
    }
}

