package io.delphiplatform.api.extapi;

import org.openapitools.jackson.nullable.JsonNullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import io.delphiplatform.api.util.model.ModelUtils;
import io.delphiplatform.api.v3.constant.DspConstants;
import io.delphiplatform.api.v3.model.Dsp;
import io.delphiplatform.api.v3.model.PlaylistOwner;
import io.delphiplatform.api.v3.model.PublicPlaylist;
import io.delphiplatform.api.v3.model.service.ImageService;
import se.michaelthelin.spotify.model_objects.specification.Followers;
import se.michaelthelin.spotify.model_objects.specification.Image;
import se.michaelthelin.spotify.model_objects.specification.Playlist;
import se.michaelthelin.spotify.model_objects.specification.PlaylistTrack;
import se.michaelthelin.spotify.model_objects.specification.User;

import static io.delphiplatform.api.v3.constant.DspConstants.SPOTIFY_NAME;
import static io.delphiplatform.api.v3.constant.DspConstants.SPOTIFY;

@Service
public class SpotifyApiPlaylistConvertor {

    private final ImageService imageService;

    @Autowired
    public SpotifyApiPlaylistConvertor(ImageService imageService) {
        this.imageService = imageService;
    }

    public PublicPlaylist toPublicPlaylist(Playlist playlist,
        List<PlaylistTrack> allPlaylistTracks,
        PublicPlaylist playlistFromDb) {
        if (playlist == null) {
            return null;
        }
        String imageUrl = Arrays.stream(playlist.getImages())
            .map(Image::getUrl)
            .findFirst().orElse(null);
        Integer playlistFollowers = Optional.ofNullable(playlist.getFollowers())
            .map(Followers::getTotal)
            .orElse(0);

        Dsp dsp = new Dsp()
            .dspId(SPOTIFY)
            .name(SPOTIFY_NAME)
            .slug(SPOTIFY);

        int tracksTotal = 0;
        if (playlist.getTracks().getTotal() > 0) {
            tracksTotal = (int) allPlaylistTracks.stream()
                .filter(trackItem -> trackItem.getTrack() != null)
                .count();
        }

        PublicPlaylist publicPlaylist = new PublicPlaylist()
            .dsp(dsp)
            .dspPlaylistId(playlist.getId())
            .name(playlist.getName())
            .numTracks(tracksTotal)
            .playlistId(ModelUtils.addDspPrefixForPlaylistId(playlist.getId(), DspConstants.SPOTIFY))
            .image(imageService.resolveImage(SPOTIFY, playlist.getId(), null, imageUrl))
            .uri(ModelUtils.createUri(playlist.getUri()))
            .description(playlist.getDescription())
            .followers(playlistFollowers)
            .publicPlaylist(playlist.getIsPublicAccess());

        if (playlistFromDb != null && playlistFromDb.getPlaylistId().equals(publicPlaylist.getPlaylistId())) {
            String countryCode = Optional.ofNullable(playlistFromDb.getCountryCode())
                .map(JsonNullable::get)
                .orElse(null);
            Integer rank = Optional.ofNullable(playlistFromDb.getRank())
                .map(r -> r.get())
                .orElse(null);
            publicPlaylist
                .countryCode(countryCode)
                .rank(rank)
                .playlistType(playlistFromDb.getPlaylistType())
                .owner(playlistFromDb.getOwner())
                .ignored(playlistFromDb.isIgnored())
                .removed(playlistFromDb.isRemoved())
                .personalised(playlistFromDb.isPersonalised());
        }

        if (playlist.getOwner() != null) {
            User user = playlist.getOwner();
            String countryCode = Optional.ofNullable(user.getCountry())
                .map(country -> Optional.ofNullable(country.name())
                    .map(String::toLowerCase)
                    .orElse(null))
                .orElse(Optional.ofNullable(playlistFromDb)
                    .map(PublicPlaylist::getOwner)
                    .filter(Objects::nonNull)
                    .map(PlaylistOwner::getOwnerCountryCode)
                    .orElse(null));

            PlaylistOwner playlistOwner = PlaylistOwner.builder()
                .username(user.getId())
                .displayName(user.getDisplayName())
                .ownerCountryCode(countryCode)
                .dsp(dsp)
                .ownerCategory(
                    Optional.ofNullable(publicPlaylist.getOwner())
                        .map(PlaylistOwner::getOwnerCategory)
                        .orElse(null))
                .build();

            publicPlaylist.setOwner(playlistOwner);
        }

        return publicPlaylist;
    }
}
