using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;

namespace NzbDrone.Core.Music
{
    public interface IArtistMetadataRepository : IBasicRepository<ArtistMetadata>
    {
        List<ArtistMetadata> FindById(List<string> foreignIds);
        bool UpsertMany(List<ArtistMetadata> data);
    }

    public class ArtistMetadataRepository : BasicRepository<ArtistMetadata>, IArtistMetadataRepository
    {
        private readonly Logger _logger;

        public ArtistMetadataRepository(IMainDatabase database, IEventAggregator eventAggregator, Logger logger)
            : base(database, eventAggregator)
        {
            _logger = logger;
        }

        public List<ArtistMetadata> FindById(List<string> foreignIds)
        {
            return Query(x => Enumerable.Contains(foreignIds, x.ForeignArtistId));
        }

        public bool UpsertMany(List<ArtistMetadata> data)
        {
            var existingMetadata = FindById(data.Select(x => x.ForeignArtistId).ToList());
            var updateMetadataList = new List<ArtistMetadata>();
            var addMetadataList = new List<ArtistMetadata>();
            var upToDateMetadataCount = 0;

            foreach (var meta in data)
            {
                var existing = existingMetadata.SingleOrDefault(x => x.ForeignArtistId == meta.ForeignArtistId);
                if (existing != null)
                {
                    if (IsPlaceholderData(meta) && !IsPlaceholderData(existing))
                    {
                        _logger.Warn($"Skipping metadata downgrade: {existing.Name} -> {meta.Name}, for artist {meta.ForeignArtistId}");
                        continue;
                    }

                    meta.UseDbFieldsFrom(existing);
                    if (!meta.Equals(existing))
                    {
                        updateMetadataList.Add(meta);
                    }
                    else
                    {
                        upToDateMetadataCount++;
                    }
                }
                else
                {
                    addMetadataList.Add(meta);
                }
            }

            UpdateMany(updateMetadataList);
            InsertMany(addMetadataList);

            _logger.Debug($"{upToDateMetadataCount} artist metadata up to date; Updating {updateMetadataList.Count}, Adding {addMetadataList.Count} artist metadata entries.");

            return updateMetadataList.Count > 0 || addMetadataList.Count > 0;
        }

        private static bool IsPlaceholderData(ArtistMetadata metadata) =>
          metadata.Name?.StartsWith("Unknown Artist", System.StringComparison.OrdinalIgnoreCase) != false ||
          metadata.Disambiguation == "Artist not found in database" ||
          metadata.Type == "Unknown";
    }
}
