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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import io.delphiplatform.api.v3.model.ChartTrackStateIncludes;
import io.delphiplatform.api.v3.model.charts.ChartTrackState;
import io.delphiplatform.api.v3.model.spotify.ChartTrackMetricsDimension;
import io.delphiplatform.api.v3.rdb.entity.apple.music.AppleMusicChartTrackEntity;
import io.delphiplatform.api.v3.rdb.entity.apple.music.AppleMusicTrackLocalizedId;
import io.delphiplatform.api.v3.view.util.Params;

@Service
@Transactional(readOnly = true)
public class AppleMusicChartTrackChangesService {

    private static final LocalDate DEFAULT_PREV_DATE_IF_NO_DATA = LocalDate.EPOCH;

    private final AppleMusicChartTrackService appleMusicChartTrackService;
    private final AppleMusicChartTrackStateService appleMusicChartTrackStateService;
    private final AppleMusicTrackService trackService;

    @Autowired
    public AppleMusicChartTrackChangesService(AppleMusicChartTrackService appleMusicChartTrackService,
        AppleMusicChartTrackStateService appleMusicChartTrackStateService,
        AppleMusicTrackService trackService) {
        this.appleMusicChartTrackService = appleMusicChartTrackService;
        this.appleMusicChartTrackStateService = appleMusicChartTrackStateService;
        this.trackService = trackService;
    }

    public List<ChartTrackState> getAppleMusicChartTracksAdditions(Params params) {
        String chartId = params.getSingleChartId();
        Integer minPosition = params.getMinPosition();
        Integer maxPosition = params.getMaxPosition();
        LocalDate requestedDate = params.getDate();
        LocalDate requestedPreviousDate = getRequestedPreviousDateOrDefault(params.getPreviousDate(), requestedDate);

        return getAppleMusicChartTracksChanges(chartId, minPosition, maxPosition, requestedPreviousDate, requestedDate,
            params.getChartTrackStateIncludes(), params.getChartTrackMetricsDimension());
    }

    public List<ChartTrackState> getAppleMusicChartTracksRemovals(Params params) {
        String chartId = params.getSingleChartId();
        Integer minPosition = params.getMinPosition();
        Integer maxPosition = params.getMaxPosition();
        LocalDate requestedDate = params.getDate();
        LocalDate requestedPreviousDate = getRequestedPreviousDateOrDefault(params.getPreviousDate(), requestedDate);

        return getAppleMusicChartTracksChanges(chartId, minPosition, maxPosition, requestedDate, requestedPreviousDate,
            params.getChartTrackStateIncludes(), params.getChartTrackMetricsDimension());
    }

    private List<ChartTrackState> getAppleMusicChartTracksChanges(String chartId,
        Integer minPosition, Integer maxPosition, LocalDate dateToExclude, LocalDate baseDate,
        Set<ChartTrackStateIncludes> includes,
        ChartTrackMetricsDimension metricsDimension) {

        Set<String> tracksToExclude = appleMusicChartTrackService
            .findTrackMetricsOnSpecificChartDate(Collections.emptySet(), chartId, dateToExclude, minPosition, maxPosition)
            .keySet().stream()
            .map(AppleMusicTrackLocalizedId::getAppleMusicTrackId)
            .collect(Collectors.toSet());

        if (metricsDimension == ChartTrackMetricsDimension.ISRC) {
            tracksToExclude.addAll(trackService.findTracksWithSameIsrcByTrackId(tracksToExclude));
        }

        Map<AppleMusicTrackLocalizedId, AppleMusicChartTrackEntity> delta = appleMusicChartTrackService
            .findTrackMetricsOnSpecificChartDateExcludeTrackIds(tracksToExclude, chartId, baseDate, minPosition, maxPosition);

        return appleMusicChartTrackStateService.getAppleMusicChartTrackStatesDistinct(includes, metricsDimension, delta);
    }

    private LocalDate getRequestedPreviousDateOrDefault(LocalDate requestedPreviousDate, LocalDate requestedDate) {
        if (requestedPreviousDate != null) {
            return requestedPreviousDate;
        }

        //default is always requestedDate-1 because currently only 'daily' charts are supported for AppleMusic
        return requestedDate.minusDays(1);
    }
}
