using Microsoft.EntityFrameworkCore;

public class PlayListSynchronizer
{
    private SpotifyApiClient _spotifyAPIClient;

    public PlayListSynchronizer(SpotifyApiClient spotifyAPIClient)
    {
        _spotifyAPIClient = spotifyAPIClient;
    }

    public async Task SynchronizePlaylistAsync(SmartPlaylistDefinition playlist)
    {
        var songsToInclude = new List<Song>();
        using (var dci = DataContext.Instance)
        {
            songsToInclude.AddRange(dci.SongSuggestions.Where(ss => ss.HasUsedSuggestion && playlist.Categories.Contains(ss.SuggestionHelper) && !songsToInclude.Contains(ss.Song)).Select(ss => ss.Song));
            songsToInclude.AddRange(playlist.ExplicitlyIncludedSongs.Where(ss => !songsToInclude.Contains(ss)));
            if (playlist.IncludesUnCategorizedSongs)
            {
                songsToInclude.AddRange(dci.SongSuggestions.Where(ss => !ss.HasUsedSuggestion && !songsToInclude.Contains(ss.Song)).Select(ss => ss.Song));
            }
            if (playlist.IncludesLikedSongs)
            {
                var userWithLikes = dci.Users.Include(u => u.LikedSongs).Where(u => u.UserId == playlist.CreatedBy.UserId).SingleOrDefault();
                var likedSongs = userWithLikes.LikedSongs;
                songsToInclude.AddRange(likedSongs.Where(s => !songsToInclude.Contains(s)));
            }
        }
        songsToInclude.RemoveAll(song => playlist.ExplicitlyExcludedSongs.Contains(song));
        var spotifyIdsToInclude = songsToInclude.Select(s => s.SpotifyId);

        var apiClient = await _spotifyAPIClient.WithUserAuthorizationAsync(playlist.CreatedBy);

        var songsAlreadyInPlaylist = await apiClient.GetSongsInPlaylist(playlist.SpotifyPlaylistId);

        var songsToAdd = spotifyIdsToInclude.Where(sti => !songsAlreadyInPlaylist.Contains(sti)).ToList();
        var songsToRemove = songsAlreadyInPlaylist.Where(sai => !spotifyIdsToInclude.Contains(sai)).ToList();

        apiClient.AddSongsToPlaylist(playlist.SpotifyPlaylistId, songsToAdd);
        apiClient.RemoveSongsFromPlaylist(playlist.SpotifyPlaylistId, songsToRemove);
    }

    public async Task SynchronizePlaylistsAsync(IList<SmartPlaylistDefinition> playlists)
    {
        foreach (var playlist in playlists)
        {
            await SynchronizePlaylistAsync(playlist);
        }
    }

    public async Task SynchronizeUserPlaylistsAsync(User user)
    {
        using (var dci = DataContext.Instance)
        {
            var userPlayLists = dci.SmartPlaylistDefinitions
                .Include(pl => pl.ExplicitlyIncludedSongs)
                .Include(pl => pl.ExplicitlyExcludedSongs)
                .Include(pl => pl.Categories)
                .Include(pl => pl.CreatedBy)
                .Where(pl => pl.CreatedBy == user).ToList();
            await SynchronizePlaylistsAsync(userPlayLists);
        }
    }
}