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

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import io.delphiplatform.api.util.CollectionUtils;
import io.delphiplatform.api.v3.model.IncludeChart;
import io.delphiplatform.api.v3.model.amazon.AmazonChartTrackSummary;
import io.delphiplatform.api.v3.rdb.entity.amazon.AmazonChartTrackLifetimeEntity;
import io.delphiplatform.api.v3.rdb.entity.amazon.AmazonTrackEntity;
import io.delphiplatform.api.v3.rdb.repository.amazon.AmazonChartTrackSummaryReportRepository;
import io.delphiplatform.api.v3.rdb.service.EntityService;
import io.delphiplatform.api.v3.rdb.service.dto.JpaPropertyPath;
import io.delphiplatform.api.v3.rdb.service.specification.SpecificationProvider;
import io.delphiplatform.api.v3.view.util.Params;

import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.AMAZON_ALBUM;
import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.AMAZON_GENRE;
import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.CHART;
import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.CHART_ID;
import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.COUNTRY_CODE;
import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.ID;
import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.ISRC;
import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.IS_SONY;
import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.TRACK;
import static io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames.TRACK_ID;

@Service
@Transactional(readOnly = true)
public class AmazonChartSummaryService extends EntityService<AmazonChartTrackLifetimeEntity> {

    private static final ImmutableMap<String, String> SORT_BY_TO_ENTITY_FIELD_MAP = ImmutableMap
        .<String, String>builder()
        .put("chart.chart_id", "chart_chart_id")
        .put("chart.total_positions", "chart_total_positions")
        .put("chart.country_code", "chart_country_code")
        .put("chart.genre", "chart_genre_name")
        .put("summary.earliest_position", "earliest_position")
        .put("summary.earliest_position_date", "earliest_position_date")
        .put("summary.latest_position", "latest_position")
        .put("summary.latest_position_date", "latest_position_date")
        .put("summary.max_position", "max_position")
        .put("summary.max_position_date", "max_position_date")
        .put("summary.min_position", "min_position")
        .put("summary.min_position_date", "min_position_date")
        .put("summary.total_days", "total_days")
        .put("track.name", "track_name")
        .put("track.amazon_track_id", "track_amazon_track_id")
        .put("track.is_sony", "track_is_sony")
        .put("track.isrc", "track_isrc")
        .put("track.release_date", "track_amazon_album_release_date")
        .build();

    private final SpecificationProvider<AmazonChartTrackLifetimeEntity> specificationProvider;
    private final AmazonArtistService artistService;

    @Autowired
    public AmazonChartSummaryService(
        AmazonChartTrackSummaryReportRepository repository,
        SpecificationProvider<AmazonChartTrackLifetimeEntity> specificationProvider,
        AmazonArtistService artistService) {
        super(repository, SORT_BY_TO_ENTITY_FIELD_MAP);
        this.specificationProvider = specificationProvider;
        this.artistService = artistService;
    }

    public List<AmazonChartTrackSummary> getAmazonChartTrackSummaries(Params params) {
        boolean includeTrack = CollectionUtils.contains(params.getIncludeChart(), IncludeChart.TRACK);

        Set<JpaPropertyPath> requestFetches = Sets.newHashSet(JpaPropertyPath.ofJoins(CHART, AMAZON_GENRE));

        if (includeTrack) {
            requestFetches.add(JpaPropertyPath.ofJoins(TRACK, AMAZON_ALBUM));
        } else {
            requestFetches.add(JpaPropertyPath.ofJoin(TRACK));
        }

        Specification<AmazonChartTrackLifetimeEntity> spec = and(Arrays.asList(
            specificationProvider.multiValueSpec(List.of(ID, CHART_ID), params.getChartId()),
            specificationProvider.multiValueSpec(ISRC, params.getIsrc()),
            specificationProvider.multiValueSpec(List.of(ID, TRACK_ID), params.getTrackId()),
            specificationProvider.multiValueSpec(List.of(ID, COUNTRY_CODE), params.getCountryCode()),
            specificationProvider.singleValueSpec(List.of(TRACK, IS_SONY), params.getIsSony()),
            specificationProvider.fetchesSpecOfPaths(requestFetches)
        ));

        List<AmazonChartTrackLifetimeEntity> entities = find(spec, getPageRequestSortByToCamelCase(params));

        Set<String> trackIds = entities.stream()
            .map(AmazonChartTrackLifetimeEntity::getTrack)
            .map(AmazonTrackEntity::getAmazonTrackId)
            .collect(Collectors.toSet());

        Map<String, String> trackToArtist = artistService.findByTrackIdToArtistNames(trackIds);

        return entities.stream().map(elem -> AmazonChartTrackSummary.of(elem, includeTrack,
                trackToArtist.get(elem.getTrack().getAmazonTrackId())))
            .collect(Collectors.toList());
    }
}