package io.delphiplatform.api.v3.view;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

import javax.transaction.NotSupportedException;

import io.delphiplatform.api.extapi.SpotifyApiService;
import io.delphiplatform.api.util.model.ModelUtils;
import io.delphiplatform.api.util.OffsetBasedPageRequest;
import io.delphiplatform.api.v3.bigtable.BigtablePublicPlaylistFollowersService;
import io.delphiplatform.api.v3.constant.CountryCodeConstant;
import io.delphiplatform.api.v3.constant.DspConstants;
import io.delphiplatform.api.v3.model.PublicPlaylist;
import io.delphiplatform.api.v3.model.PublicPlaylistFollowers;
import io.delphiplatform.api.v3.model.PublicPlaylists;
import io.delphiplatform.api.v3.model.PublicPlaylistsFollowers;
import io.delphiplatform.api.v3.model.SortOrder;
import io.delphiplatform.api.v3.rdb.service.playlist_public.PlaylistPublicService;
import io.delphiplatform.api.v3.view.util.Params;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("${spring.data.rest.base-path:/v3}")
public class PlaylistsPublicApiController implements PlaylistsPublicApi {

    private final PlaylistPublicService playlistPublicService;
    private final SpotifyApiService spotifyApiService;
    private final BigtablePublicPlaylistFollowersService bigtablePublicPlaylistFollowersService;

    public PlaylistsPublicApiController(
        PlaylistPublicService playlistPublicService,
        SpotifyApiService spotifyApiService,
        BigtablePublicPlaylistFollowersService bigtablePublicPlaylistFollowersService
    ) {
        this.playlistPublicService = playlistPublicService;
        this.spotifyApiService = spotifyApiService;
        this.bigtablePublicPlaylistFollowersService = bigtablePublicPlaylistFollowersService;
    }

    @Override
    public ResponseEntity<PublicPlaylist> findOnePublic(String playlistId, String appleCountryCode) {
        String countryCode = null;

        if (ModelUtils.isPlaylistOfDsp(playlistId, DspConstants.APPLE)) {
            if (StringUtils.isEmpty(appleCountryCode)) {
                countryCode = CountryCodeConstant.US;
            } else {
                countryCode = appleCountryCode;
            }
        }

        return ResponseEntity.ok(playlistPublicService.findOne(
            ModelUtils.composePlaylistKeyFromValues(playlistId, countryCode))
        );
    }

    @Override
    public ResponseEntity<PublicPlaylist> findOnePublicCurrent(String playlistId, String appleCountryCode) {
        if (!ModelUtils.isPlaylistOfDsp(playlistId, DspConstants.APPLE)
            && !ModelUtils.isPlaylistOfDsp(playlistId, DspConstants.SPOTIFY)) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                "playlist_id parameter has unsupported value. Must be a playlist id with dsp prefix ('spotify|apple_xxx'). "
                    + "You provided: " + playlistId);
        }

        if (ModelUtils.isPlaylistOfDsp(playlistId, DspConstants.APPLE)) {
            return findOnePublic(playlistId, appleCountryCode);
        }
        return ResponseEntity.ok(spotifyApiService.getPlaylistAsPublicPlaylist(playlistId));
    }

    @Override
    public ResponseEntity<PublicPlaylists> getSearchDataPublic(List<String> dsps, List<String> playlistIds,
        Set<String> countryCodes, boolean includeIgnored, boolean includeRemoved,
        Integer limit, Integer offset, String sortBy, SortOrder sortOrder) {
        List<PublicPlaylist> items = playlistPublicService
            .findByDsp(dsps, playlistIds, countryCodes, includeIgnored, includeRemoved,
                OffsetBasedPageRequest.ofParamsKeepCase(offset, limit, sortOrder, sortBy));
        return ResponseEntity.ok(new PublicPlaylists().items(items).count(items.size()));
    }

    @Override
    public CompletableFuture<ResponseEntity<PublicPlaylistsFollowers>> publicPlaylistsFollowers(Params params) {
        if (params.getPlaylistId().stream()
            .anyMatch(playlistId -> !ModelUtils.isPlaylistOfDsp(playlistId, DspConstants.SPOTIFY))) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "only Spotify dsp-prefixed playlists are supported");
        }

        try {
            CompletableFuture<List<PublicPlaylistFollowers>> playlistFollowers =
                bigtablePublicPlaylistFollowersService.getPlaylistsFollowers(params);

            return playlistFollowers.thenApply(followers -> ResponseEntity.ok(
                new PublicPlaylistsFollowers(followers)
            ));
        } catch (NotSupportedException e) {
            log.error("Error while getting playlist followers.", e);
            throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED, e.getMessage());
        }
    }
}
