// Path: src/main/java/com/github/sandokandias/payments/domain/command/PerformPayment.java
// @Value(staticConstructor = "commandOf")
// public class PerformPayment implements PaymentCommand {
//     private final CustomerId customerId;
//     private final PaymentIntent paymentIntent;
//     private final PaymentMethod paymentMethod;
//     private final Transaction transaction;
//     private final LocalDateTime timestamp = LocalDateTime.now();
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/command/validation/PerformPaymentValidator.java
// @Component
// public class PerformPaymentValidator implements CommandValidation<PerformPayment> {
// 
//     @Override
//     public Either<CommandFailure, PerformPayment> acceptOrReject(PerformPayment command) {
// 
//         return Either.right(command);
//     }
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/entity/PaymentEventRepository.java
// public interface PaymentEventRepository {
//     CompletionStage<PaymentEventId> store(PaymentEvent paymentEvent);
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/event/PaymentRequested.java
// @Value(staticConstructor = "eventOf")
// public class PaymentRequested implements PaymentEvent {
//     private final PaymentEventId eventId = new PaymentEventId();
//     private final PaymentId paymentId;
//     private final CustomerId customerId;
//     private final PaymentIntent paymentIntent;
//     private final PaymentMethod paymentMethod;
//     private final Transaction transaction;
//     private final LocalDateTime timestamp;
// 
//     @Override
//     public PaymentEventType getEventType() {
//         return PaymentEventType.PAYMENT_REQUESTED;
//     }
// 
//     @Override
//     public LocalDateTime getTimestamp() {
//         return timestamp;
//     }
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/shared/CommandFailure.java
// @AllArgsConstructor
// public class CommandFailure {
//     public final Set<I18nCode> codes;
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/shared/CommandHandler.java
// public interface CommandHandler<C extends Command, E extends Event, ID> {
//     CompletionStage<Either<CommandFailure, E>> handle(C command, ID entityId);
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/vo/PaymentEventId.java
// public class PaymentEventId extends RandomUUID {
// 
//     @Override
//     protected String getPrefix() {
//         return "PEV-%s";
//     }
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/vo/PaymentId.java
// public class PaymentId extends RandomUUID {
// 
//     public PaymentId() {
//         super();
//     }
// 
//     public PaymentId(String id) {
//         super(id);
//     }
// 
//     @Override
//     protected String getPrefix() {
//         return "PAY-%s";
//     }
// }


import com.github.sandokandias.payments.domain.command.PerformPayment;
import com.github.sandokandias.payments.domain.command.validation.PerformPaymentValidator;
import com.github.sandokandias.payments.domain.entity.PaymentEventRepository;
import com.github.sandokandias.payments.domain.event.PaymentRequested;
import com.github.sandokandias.payments.domain.shared.CommandFailure;
import com.github.sandokandias.payments.domain.shared.CommandHandler;
import com.github.sandokandias.payments.domain.vo.PaymentEventId;
import com.github.sandokandias.payments.domain.vo.PaymentId;
import io.vavr.control.Either;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
package com.github.sandokandias.payments.domain.command.handler;



@Component
public class PerformPaymentHandler implements
        CommandHandler<PerformPayment, PaymentRequested, PaymentId> {

    private static final Logger LOG = LoggerFactory.getLogger(PerformPaymentHandler.class);

    private final PaymentEventRepository paymentEventRepository;
    private final PerformPaymentValidator performPaymentValidator;

    PerformPaymentHandler(PaymentEventRepository paymentEventRepository,
                          PerformPaymentValidator performPaymentValidator) {
        this.paymentEventRepository = paymentEventRepository;
        this.performPaymentValidator = performPaymentValidator;
    }

    @Override
    public CompletionStage<Either<CommandFailure, PaymentRequested>> handle(PerformPayment command, PaymentId entityId) {

        LOG.debug("Handle command {}", command);

        return performPaymentValidator.acceptOrReject(command).fold(
                reject -> CompletableFuture.completedFuture(Either.left(reject)),
                accept -> {
                    PaymentRequested event = PaymentRequested.eventOf(
                            entityId,
                            command.getCustomerId(),
                            command.getPaymentIntent(),
                            command.getPaymentMethod(),
                            command.getTransaction(),
                            command.getTimestamp()
                    );
// Path: src/main/java/com/github/sandokandias/payments/domain/command/PerformPayment.java
// @Value(staticConstructor = "commandOf")
// public class PerformPayment implements PaymentCommand {
//     private final CustomerId customerId;
//     private final PaymentIntent paymentIntent;
//     private final PaymentMethod paymentMethod;
//     private final Transaction transaction;
//     private final LocalDateTime timestamp = LocalDateTime.now();
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/command/validation/PerformPaymentValidator.java
// @Component
// public class PerformPaymentValidator implements CommandValidation<PerformPayment> {
// 
//     @Override
//     public Either<CommandFailure, PerformPayment> acceptOrReject(PerformPayment command) {
// 
//         return Either.right(command);
//     }
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/entity/PaymentEventRepository.java
// public interface PaymentEventRepository {
//     CompletionStage<PaymentEventId> store(PaymentEvent paymentEvent);
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/event/PaymentRequested.java
// @Value(staticConstructor = "eventOf")
// public class PaymentRequested implements PaymentEvent {
//     private final PaymentEventId eventId = new PaymentEventId();
//     private final PaymentId paymentId;
//     private final CustomerId customerId;
//     private final PaymentIntent paymentIntent;
//     private final PaymentMethod paymentMethod;
//     private final Transaction transaction;
//     private final LocalDateTime timestamp;
// 
//     @Override
//     public PaymentEventType getEventType() {
//         return PaymentEventType.PAYMENT_REQUESTED;
//     }
// 
//     @Override
//     public LocalDateTime getTimestamp() {
//         return timestamp;
//     }
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/shared/CommandFailure.java
// @AllArgsConstructor
// public class CommandFailure {
//     public final Set<I18nCode> codes;
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/shared/CommandHandler.java
// public interface CommandHandler<C extends Command, E extends Event, ID> {
//     CompletionStage<Either<CommandFailure, E>> handle(C command, ID entityId);
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/vo/PaymentEventId.java
// public class PaymentEventId extends RandomUUID {
// 
//     @Override
//     protected String getPrefix() {
//         return "PEV-%s";
//     }
// }
// 
// Path: src/main/java/com/github/sandokandias/payments/domain/vo/PaymentId.java
// public class PaymentId extends RandomUUID {
// 
//     public PaymentId() {
//         super();
//     }
// 
//     public PaymentId(String id) {
//         super(id);
//     }
// 
//     @Override
//     protected String getPrefix() {
//         return "PAY-%s";
//     }
// }


// Path: src/main/java/com/github/sandokandias/payments/domain/command/handler/PerformPaymentHandler.java
import com.github.sandokandias.payments.domain.command.PerformPayment;
import com.github.sandokandias.payments.domain.command.validation.PerformPaymentValidator;
import com.github.sandokandias.payments.domain.entity.PaymentEventRepository;
import com.github.sandokandias.payments.domain.event.PaymentRequested;
import com.github.sandokandias.payments.domain.shared.CommandFailure;
import com.github.sandokandias.payments.domain.shared.CommandHandler;
import com.github.sandokandias.payments.domain.vo.PaymentEventId;
import com.github.sandokandias.payments.domain.vo.PaymentId;
import io.vavr.control.Either;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

package com.github.sandokandias.payments.domain.command.handler;



@Component
public class PerformPaymentHandler implements
        CommandHandler<PerformPayment, PaymentRequested, PaymentId> {

    private static final Logger LOG = LoggerFactory.getLogger(PerformPaymentHandler.class);

    private final PaymentEventRepository paymentEventRepository;
    private final PerformPaymentValidator performPaymentValidator;

    PerformPaymentHandler(PaymentEventRepository paymentEventRepository,
                          PerformPaymentValidator performPaymentValidator) {
        this.paymentEventRepository = paymentEventRepository;
        this.performPaymentValidator = performPaymentValidator;
    }

    @Override
    public CompletionStage<Either<CommandFailure, PaymentRequested>> handle(PerformPayment command, PaymentId entityId) {

        LOG.debug("Handle command {}", command);

        return performPaymentValidator.acceptOrReject(command).fold(
                reject -> CompletableFuture.completedFuture(Either.left(reject)),
                accept -> {
                    PaymentRequested event = PaymentRequested.eventOf(
                            entityId,
                            command.getCustomerId(),
                            command.getPaymentIntent(),
                            command.getPaymentMethod(),
                            command.getTransaction(),
                            command.getTimestamp()
                    );
                    CompletionStage<PaymentEventId> storePromise = paymentEventRepository.store(event);