// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/Utils.java
// @NotNull
// public static <EventT extends BaseEvent> String ids(
//         @NotNull List<EventT> events) {
//     return events.stream()
//             .map(i -> String.valueOf(i.getId()))
//             .collect(JOIN_EVENT_IDS);
// }
// 
// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/Utils.java
// @NotNull
// public static <EventT extends BaseEvent> String stringify(
//         @NotNull List<EventT> events) {
//     return events.stream()
//             .map(EventT::toString)
//             .collect(JOIN_EVENTS);
// }


import com.github.rahulsom.grooves.api.EventApplyOutcome;
import com.github.rahulsom.grooves.api.GroovesException;
import com.github.rahulsom.grooves.api.events.BaseEvent;
import com.github.rahulsom.grooves.api.events.DeprecatedBy;
import com.github.rahulsom.grooves.api.events.Deprecates;
import com.github.rahulsom.grooves.api.events.RevertEvent;
import com.github.rahulsom.grooves.api.snapshots.internal.BaseSnapshot;
import io.reactivex.Flowable;
import org.jetbrains.annotations.NotNull;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.github.rahulsom.grooves.api.EventApplyOutcome.RETURN;
import static com.github.rahulsom.grooves.queries.internal.Utils.ids;
import static com.github.rahulsom.grooves.queries.internal.Utils.stringify;
import static io.reactivex.Flowable.*;
     * @return The snapshot after applying the Deprecates event
     */
    Flowable<SnapshotT> applyDeprecates(
            final Deprecates<AggregateT, EventIdT, EventT> event,
            final BaseQuery<AggregateT, EventIdT, EventT, SnapshotIdT,
                    SnapshotT> query,
            final Flowable<EventT> events,
            final List<Deprecates<AggregateT, EventIdT, EventT>> deprecatesEvents,
            AggregateT aggregate) {

        log.info("        -> {} will cause recomputation", event);
        final SnapshotT newSnapshot = query.createEmptySnapshot();
        newSnapshot.setAggregate(aggregate);

        return fromPublisher(event.getConverseObservable()).flatMap(converse ->
                fromPublisher(event.getDeprecatedObservable())
                        .flatMap(deprecatedAggregate -> {
                            log.debug("        -> Deprecated Aggregate is: {}. Converse is: {}",
                                    deprecatedAggregate, converse);
                            query.addToDeprecates(newSnapshot, deprecatedAggregate);

                            Flowable<EventT> concatenatedEvents =
                                    events.concatWith(
                                            fromPublisher(query.findEventsBefore((EventT) converse))
                                    ).cache();
                            return concatenatedEvents
                                    .filter(it -> !isDeprecatesOrConverse(event, converse, it))
                                    .toSortedList(Comparator.comparing(EventT::getTimestamp))
                                    .toFlowable()
                                    .doOnNext(it ->
// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/Utils.java
// @NotNull
// public static <EventT extends BaseEvent> String ids(
//         @NotNull List<EventT> events) {
//     return events.stream()
//             .map(i -> String.valueOf(i.getId()))
//             .collect(JOIN_EVENT_IDS);
// }
// 
// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/Utils.java
// @NotNull
// public static <EventT extends BaseEvent> String stringify(
//         @NotNull List<EventT> events) {
//     return events.stream()
//             .map(EventT::toString)
//             .collect(JOIN_EVENTS);
// }


// Path: grooves-api/src/main/java/com/github/rahulsom/grooves/queries/internal/QueryExecutor.java
import com.github.rahulsom.grooves.api.EventApplyOutcome;
import com.github.rahulsom.grooves.api.GroovesException;
import com.github.rahulsom.grooves.api.events.BaseEvent;
import com.github.rahulsom.grooves.api.events.DeprecatedBy;
import com.github.rahulsom.grooves.api.events.Deprecates;
import com.github.rahulsom.grooves.api.events.RevertEvent;
import com.github.rahulsom.grooves.api.snapshots.internal.BaseSnapshot;
import io.reactivex.Flowable;
import org.jetbrains.annotations.NotNull;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.github.rahulsom.grooves.api.EventApplyOutcome.RETURN;
import static com.github.rahulsom.grooves.queries.internal.Utils.ids;
import static com.github.rahulsom.grooves.queries.internal.Utils.stringify;
import static io.reactivex.Flowable.*;

     * @return The snapshot after applying the Deprecates event
     */
    Flowable<SnapshotT> applyDeprecates(
            final Deprecates<AggregateT, EventIdT, EventT> event,
            final BaseQuery<AggregateT, EventIdT, EventT, SnapshotIdT,
                    SnapshotT> query,
            final Flowable<EventT> events,
            final List<Deprecates<AggregateT, EventIdT, EventT>> deprecatesEvents,
            AggregateT aggregate) {

        log.info("        -> {} will cause recomputation", event);
        final SnapshotT newSnapshot = query.createEmptySnapshot();
        newSnapshot.setAggregate(aggregate);

        return fromPublisher(event.getConverseObservable()).flatMap(converse ->
                fromPublisher(event.getDeprecatedObservable())
                        .flatMap(deprecatedAggregate -> {
                            log.debug("        -> Deprecated Aggregate is: {}. Converse is: {}",
                                    deprecatedAggregate, converse);
                            query.addToDeprecates(newSnapshot, deprecatedAggregate);

                            Flowable<EventT> concatenatedEvents =
                                    events.concatWith(
                                            fromPublisher(query.findEventsBefore((EventT) converse))
                                    ).cache();
                            return concatenatedEvents
                                    .filter(it -> !isDeprecatesOrConverse(event, converse, it))
                                    .toSortedList(Comparator.comparing(EventT::getTimestamp))
                                    .toFlowable()
                                    .doOnNext(it ->
                                            log.debug("     Reassembled Events: {}", stringify(it)))