package io.delphiplatform.api.v3.rdb.service;

import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class BreakdownHelper {

    private static final String STATIC_KEY = "static_key";

    public <T, R, K1, K2> Map<K1, Map<K2, R>> breakdown(
        Stream<T> items,
        Function<T, K1> key1Extractor,
        Function<T, K2> key2Extractor,
        BiConsumer<T, R> merger,
        Supplier<R> newItemBuilder
    ) {
        Map<K1, List<T>> key1Aggregation = items.collect(Collectors.groupingBy(key1Extractor));
        Map<K1, Map<K2, List<T>>> key2Aggregation = key1Aggregation.entrySet().stream()
            .collect(Collectors.toMap(Entry::getKey, e -> e.getValue().stream().collect(
                Collectors.groupingBy(key2Extractor))));

        return key2Aggregation.entrySet().stream()
            .collect(Collectors.toMap(Entry::getKey, key1Entry -> key1Entry.getValue().entrySet()
                .stream().collect(
                    Collectors.toMap(Entry::getKey, key2Entry -> {
                        R r = newItemBuilder.get();
                        key2Entry.getValue().forEach(i -> merger.accept(i, r));
                        return r;
                    }))));
    }

    public <T, R, K1> Map<K1, R> breakdown(
        Stream<T> items,
        Function<T, K1> key1Extractor,
        BiConsumer<T, R> merger,
        Supplier<R> newItemBuilder
    ) {
        return breakdown(items, a -> STATIC_KEY, key1Extractor, merger, newItemBuilder).get(STATIC_KEY);
    }


}
