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

import com.google.common.collect.ImmutableMap;

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.video.ShazamChartTrackSummary;
import io.delphiplatform.api.v3.rdb.entity.CommonJpaPropertyNames;
import io.delphiplatform.api.v3.rdb.entity.video.ShazamChartTrackSummaryReportEntity;
import io.delphiplatform.api.v3.rdb.repository.ShazamChartTrackSummaryReportRepository;
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;

@Service
@Transactional(readOnly = true)
public class ShazamChartSummaryService extends EntityService<ShazamChartTrackSummaryReportEntity> {

    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.country_code", "chart_region_region_id")
        .put("chart.total_positions", "chart_num_tracks")
        .put("chart.city_id", "chart_shazam_city_shazam_city_id")
        .put("chart.city_name", "chart_shazam_city_shazam_city_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")
        .build();

    private static final Set<JpaPropertyPath> FETCHES =
        Set.of(JpaPropertyPath.ofJoin(CommonJpaPropertyNames.TRACK),
            JpaPropertyPath.ofJoins(CommonJpaPropertyNames.CHART, CommonJpaPropertyNames.SHAZAM_CITY)
        );

    private final SpecificationProvider<ShazamChartTrackSummaryReportEntity> specificationProvider;
    private final ShazamArtistService artistService;

    @Autowired
    public ShazamChartSummaryService(ShazamChartTrackSummaryReportRepository repository,
        SpecificationProvider<ShazamChartTrackSummaryReportEntity> specificationProvider,
        ShazamArtistService artistService) {
        super(repository, SORT_BY_TO_ENTITY_FIELD_MAP);
        this.specificationProvider = specificationProvider;
        this.artistService = artistService;
    }

    public List<ShazamChartTrackSummary> getShazamChartTrackSummaries(Params params) {

        Specification<ShazamChartTrackSummaryReportEntity> spec = and(Arrays.asList(
            specificationProvider.singleValueSpec(List.of("id", "chartId"), params.getChartId()),
            specificationProvider.multiValueSpec("isrc", params.getIsrc()),
            specificationProvider.multiValueSpec(List.of("id", "shazamCityId"), params.getCityCode()),
            specificationProvider.multiValueSpec(List.of("id", "countryCode"), params.getCountryCode()),
            specificationProvider.singleValueSpec("isSony", params.getIsSony(),
                CommonJpaPropertyNames.TRACK),
            specificationProvider.fetchesSpecOfPaths(FETCHES, true)
        ));

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

        Map<String, List<String>> isrcToArtists = artistService.findByIsrcToArtistNames(entities
            .stream()
            .map(ShazamChartTrackSummaryReportEntity::getIsrc)
            .collect(Collectors.toSet()));

        boolean includeTrack = CollectionUtils.contains(params.getIncludeChart(), IncludeChart.TRACK);
        return entities.stream().map(elem -> ShazamChartTrackSummary.of(elem, includeTrack,
                isrcToArtists.get(elem.getIsrc())))
            .collect(Collectors.toList());
    }

}
