package io.delphiplatform.api.v3.bigtable.processing;

import com.google.common.collect.ImmutableList;

import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import io.delphiplatform.api.util.CollectionUtils;
import io.delphiplatform.api.v3.bigtable.processing.groupbykey.TrackPositionPublicGroupByKey;
import io.delphiplatform.api.v3.model.TrackPosition;
import lombok.extern.slf4j.Slf4j;

import static io.delphiplatform.api.v3.bigtable.processing.GroupByFieldEnum.COUNTRY_CODE;
import static io.delphiplatform.api.v3.bigtable.processing.GroupByFieldEnum.CURRENT_POSITION;
import static io.delphiplatform.api.v3.bigtable.processing.GroupByFieldEnum.DATE;
import static io.delphiplatform.api.v3.bigtable.processing.GroupByFieldEnum.DSP;
import static io.delphiplatform.api.v3.bigtable.processing.GroupByFieldEnum.ISRC;
import static io.delphiplatform.api.v3.bigtable.processing.GroupByFieldEnum.PLAYLIST_ID;

@Slf4j
@Service
public class TrackPositionPublicAggregator {

    private final List<GroupByFieldEnum> PLAYLIST_GROUP_BY = ImmutableList.of(
        ISRC, DATE, DSP, PLAYLIST_ID, COUNTRY_CODE, CURRENT_POSITION
    );

    public <T extends TrackPosition> Stream<T> groupBy(Stream<T> trackPositions) {
        return groupBy(trackPositions, PLAYLIST_GROUP_BY);
    }

    private <T extends TrackPosition> Stream<T> groupBy(
        Stream<T> trackPositions,
        List<GroupByFieldEnum> groupByFields
    ) {
        return trackPositions
            .collect(Collectors.groupingBy(followers -> new TrackPositionPublicGroupByKey(followers, groupByFields)))
            .entrySet().stream()
            .map(entry -> {
                TrackPositionPublicGroupByKey key = entry.getKey();
                List<T> group = entry.getValue();
                T aggregationResult = getAggregationResult(group, groupByFields);
                key.populateTrackPosition(aggregationResult);
                return aggregationResult;
            });
    }

    public static <T extends TrackPosition> T getAggregationResult(
        List<T> group, List<GroupByFieldEnum> groupByFields
    ) {
        if (group.size() > 1) {
            log.warn("Data issue: having more then one entity per {} combination for group: {}", groupByFields, group);
        }
        return CollectionUtils.isEmpty(group) ? null : group.get(0);
    }

}
