// Path: mail-service/src/main/java/com/apssouza/eventsourcing/aggregates/EmailAggregate.java
// public class EmailAggregate extends AbstractAggregate implements Aggregate {
// 
//     private final Email state;
// 
//     public EmailAggregate(String uuid, List<AppEvent> changes) {
//         this(uuid, changes, new Email());
//     }
// 
//     public EmailAggregate(String uuid, List<AppEvent> changes, Email state) {
//         this.uuid = uuid;
//         this.changes = changes;
//         this.state = state;
//     }
// 
//     public EmailAggregate create(EmailCreateCommand command) throws Exception {
//         if (state.getState() != null) {
//             throw new Exception("Is not possible to edit a deleted email");
//         }
//         return applyChange(new EmailCreatedEvent(uuid, command.getEmail()));
//     }
// 
//     public EmailAggregate send(EmailSendCommand command) throws Exception {
//         if (state.getState() == EmailState.DELETED) {
//             throw new Exception("Is not possible to edit a deleted email");
//         }
//         return applyChange(new EmailSentEvent(
//                 command.getUuid(),
//                 getState().setState(EmailState.SENT)));
//     }
// 
//     public EmailAggregate delivery(EmailDeliveryCommand command) throws Exception {
//         if (state.getState() == EmailState.DELETED) {
//             throw new Exception("Is not possible to edit a deleted email");
//         }
//         return applyChange(new EmailDeliveredEvent(
//                 command.getUuid(),
//                 getState().setState(EmailState.DELIVERED)
//         ));
//     }
// 
//     public EmailAggregate delete(EmailDeleteCommand command) throws Exception {
//         if (state.getState() == EmailState.DELETED) {
//             throw new Exception("Is not possible to delete a deleted email");
//         }
//         return applyChange(new EmailDeletedEvent(uuid,
//                 getState().setState(EmailState.DELETED)
//         ));
//     }
// 
//     private EmailAggregate apply(AppEvent event) {
//         if (event instanceof EmailCreatedEvent) {
//             return this.apply((EmailCreatedEvent) event);
//         }
//         if (event instanceof EmailSentEvent) {
//             return this.apply((EmailSentEvent) event);
//         }
//         if (event instanceof EmailDeliveredEvent) {
//             return this.apply((EmailDeliveredEvent) event);
//         }
//         if (event instanceof EmailDeletedEvent) {
//             return this.apply((EmailDeletedEvent) event);
//         }
//         throw new IllegalArgumentException("Cannot handle event " + event.getClass());
// 
//     }
// 
//     private EmailAggregate apply(EmailCreatedEvent event) {
//         return new EmailAggregate(uuid, changes, event.getEmail());
//     }
// 
//     private EmailAggregate apply(EmailDeletedEvent event) {
//         return new EmailAggregate(uuid, changes, event.getEmail());
//     }
// 
//     private EmailAggregate apply(EmailSentEvent event) {
//         return new EmailAggregate(uuid, changes, event.getEmail());
//     }
// 
//     private EmailAggregate apply(EmailDeliveredEvent event) {
//         return new EmailAggregate(uuid, changes, event.getEmail());
//     }
// 
//     public static EmailAggregate from(String uuid, List<AppEvent> history) {
// 
//         EmailAggregate emailAggregate = new EmailAggregate(uuid, new CopyOnWriteArrayList(), new Email());
// 
//         return history
//                 .stream()
//                 .reduce(emailAggregate,
//                         (tx, event) -> tx.applyChange(event, false),
//                         (t1, t2) -> {
//                             throw new UnsupportedOperationException();
//                         }
//                 );
//     }
// 
//     private EmailAggregate applyChange(AppEvent event, boolean isNew) {
//         final EmailAggregate item = this.apply(event);
//         if (isNew) {
//             return new EmailAggregate(item.getUuid(), appendChange(event), item.getState());
//         } else {
//             return item;
//         }
//     }
// 
//     private EmailAggregate applyChange(EmailEvent event) {
//         return applyChange(event, true);
//     }
// 
//     @Override
//     public EmailAggregate markChangesAsCommitted() {
//         return new EmailAggregate(uuid, new CopyOnWriteArrayList(), state);
//     }
// 
//     public Email getState() {
//         return state;
//     }
// 
// }
// 
// Path: mail-service/src/main/java/com/apssouza/eventsourcing/services/EventSourcingService.java
// public interface EventSourcingService {
//     
//     Aggregate save(Aggregate aggregate) ;
//     
//     List<AppEvent> getRelatedEvents(String uuid);
//     
//     EventStream getAggregate(String uuid);
// }
// 
// Path: todo-infra/src/main/java/com/apssouza/infra/AppEvent.java
// public interface AppEvent {
// 
//     String uuid();
// 
//     Instant when();
// 
// }
// 
// Path: todo-infra/src/main/java/com/apssouza/infra/EventPublisher.java
// @Component
// @EnableBinding(Source.class)
// public class EventPublisher {
//     
//     private final MessageChannel channel;
// 
//     private final ApplicationEventPublisher publisher;
// 
//     /**
//      *
//      * @param source
//      * @param publisher
//      */
//     @Autowired
//     public EventPublisher(Source source, ApplicationEventPublisher publisher) {
//         this.channel = source.output();
//         this.publisher = publisher;
//     }
// 
//     public void publish(AppEvent event) {
//         publisher.publishEvent(event);
//     }
// 
//     public void stream(AppEvent event) {
//         Message<AppEvent> msg = MessageBuilder.withPayload(event)
//                 .setHeader("type", event.getClass().getSimpleName())
//                 .build();
//         channel.send(msg);
//         System.out.println("published");
//     }
// 
// }


import com.apssouza.eventsourcing.aggregates.EmailAggregate;
import com.apssouza.eventsourcing.services.EventSourcingService;
import com.apssouza.infra.AppEvent;
import com.apssouza.infra.EventPublisher;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
package com.apssouza.eventsourcing.commands;


/**
 * Email command service handler. Deal with the business requirements before
 * send the command
 *
 * @author apssouza
 */
@Service
@Transactional
public class EmailCommandHandler  {

    private final EventSourcingService eventSourcingService;

    private final EventPublisher eventPublisher;

    public EmailCommandHandler(
// Path: mail-service/src/main/java/com/apssouza/eventsourcing/aggregates/EmailAggregate.java
// public class EmailAggregate extends AbstractAggregate implements Aggregate {
// 
//     private final Email state;
// 
//     public EmailAggregate(String uuid, List<AppEvent> changes) {
//         this(uuid, changes, new Email());
//     }
// 
//     public EmailAggregate(String uuid, List<AppEvent> changes, Email state) {
//         this.uuid = uuid;
//         this.changes = changes;
//         this.state = state;
//     }
// 
//     public EmailAggregate create(EmailCreateCommand command) throws Exception {
//         if (state.getState() != null) {
//             throw new Exception("Is not possible to edit a deleted email");
//         }
//         return applyChange(new EmailCreatedEvent(uuid, command.getEmail()));
//     }
// 
//     public EmailAggregate send(EmailSendCommand command) throws Exception {
//         if (state.getState() == EmailState.DELETED) {
//             throw new Exception("Is not possible to edit a deleted email");
//         }
//         return applyChange(new EmailSentEvent(
//                 command.getUuid(),
//                 getState().setState(EmailState.SENT)));
//     }
// 
//     public EmailAggregate delivery(EmailDeliveryCommand command) throws Exception {
//         if (state.getState() == EmailState.DELETED) {
//             throw new Exception("Is not possible to edit a deleted email");
//         }
//         return applyChange(new EmailDeliveredEvent(
//                 command.getUuid(),
//                 getState().setState(EmailState.DELIVERED)
//         ));
//     }
// 
//     public EmailAggregate delete(EmailDeleteCommand command) throws Exception {
//         if (state.getState() == EmailState.DELETED) {
//             throw new Exception("Is not possible to delete a deleted email");
//         }
//         return applyChange(new EmailDeletedEvent(uuid,
//                 getState().setState(EmailState.DELETED)
//         ));
//     }
// 
//     private EmailAggregate apply(AppEvent event) {
//         if (event instanceof EmailCreatedEvent) {
//             return this.apply((EmailCreatedEvent) event);
//         }
//         if (event instanceof EmailSentEvent) {
//             return this.apply((EmailSentEvent) event);
//         }
//         if (event instanceof EmailDeliveredEvent) {
//             return this.apply((EmailDeliveredEvent) event);
//         }
//         if (event instanceof EmailDeletedEvent) {
//             return this.apply((EmailDeletedEvent) event);
//         }
//         throw new IllegalArgumentException("Cannot handle event " + event.getClass());
// 
//     }
// 
//     private EmailAggregate apply(EmailCreatedEvent event) {
//         return new EmailAggregate(uuid, changes, event.getEmail());
//     }
// 
//     private EmailAggregate apply(EmailDeletedEvent event) {
//         return new EmailAggregate(uuid, changes, event.getEmail());
//     }
// 
//     private EmailAggregate apply(EmailSentEvent event) {
//         return new EmailAggregate(uuid, changes, event.getEmail());
//     }
// 
//     private EmailAggregate apply(EmailDeliveredEvent event) {
//         return new EmailAggregate(uuid, changes, event.getEmail());
//     }
// 
//     public static EmailAggregate from(String uuid, List<AppEvent> history) {
// 
//         EmailAggregate emailAggregate = new EmailAggregate(uuid, new CopyOnWriteArrayList(), new Email());
// 
//         return history
//                 .stream()
//                 .reduce(emailAggregate,
//                         (tx, event) -> tx.applyChange(event, false),
//                         (t1, t2) -> {
//                             throw new UnsupportedOperationException();
//                         }
//                 );
//     }
// 
//     private EmailAggregate applyChange(AppEvent event, boolean isNew) {
//         final EmailAggregate item = this.apply(event);
//         if (isNew) {
//             return new EmailAggregate(item.getUuid(), appendChange(event), item.getState());
//         } else {
//             return item;
//         }
//     }
// 
//     private EmailAggregate applyChange(EmailEvent event) {
//         return applyChange(event, true);
//     }
// 
//     @Override
//     public EmailAggregate markChangesAsCommitted() {
//         return new EmailAggregate(uuid, new CopyOnWriteArrayList(), state);
//     }
// 
//     public Email getState() {
//         return state;
//     }
// 
// }
// 
// Path: mail-service/src/main/java/com/apssouza/eventsourcing/services/EventSourcingService.java
// public interface EventSourcingService {
//     
//     Aggregate save(Aggregate aggregate) ;
//     
//     List<AppEvent> getRelatedEvents(String uuid);
//     
//     EventStream getAggregate(String uuid);
// }
// 
// Path: todo-infra/src/main/java/com/apssouza/infra/AppEvent.java
// public interface AppEvent {
// 
//     String uuid();
// 
//     Instant when();
// 
// }
// 
// Path: todo-infra/src/main/java/com/apssouza/infra/EventPublisher.java
// @Component
// @EnableBinding(Source.class)
// public class EventPublisher {
//     
//     private final MessageChannel channel;
// 
//     private final ApplicationEventPublisher publisher;
// 
//     /**
//      *
//      * @param source
//      * @param publisher
//      */
//     @Autowired
//     public EventPublisher(Source source, ApplicationEventPublisher publisher) {
//         this.channel = source.output();
//         this.publisher = publisher;
//     }
// 
//     public void publish(AppEvent event) {
//         publisher.publishEvent(event);
//     }
// 
//     public void stream(AppEvent event) {
//         Message<AppEvent> msg = MessageBuilder.withPayload(event)
//                 .setHeader("type", event.getClass().getSimpleName())
//                 .build();
//         channel.send(msg);
//         System.out.println("published");
//     }
// 
// }


// Path: mail-service/src/main/java/com/apssouza/eventsourcing/commands/EmailCommandHandler.java
import com.apssouza.eventsourcing.aggregates.EmailAggregate;
import com.apssouza.eventsourcing.services.EventSourcingService;
import com.apssouza.infra.AppEvent;
import com.apssouza.infra.EventPublisher;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

package com.apssouza.eventsourcing.commands;


/**
 * Email command service handler. Deal with the business requirements before
 * send the command
 *
 * @author apssouza
 */
@Service
@Transactional
public class EmailCommandHandler  {

    private final EventSourcingService eventSourcingService;

    private final EventPublisher eventPublisher;

    public EmailCommandHandler(
            EventSourcingService eventSourcingService,