using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
    /// 
    /// Class CollectionPostScanTask.
    /// 
    public class CollectionPostScanTask : ILibraryPostScanTask
    {
        private readonly ILibraryManager _libraryManager;
        private readonly ICollectionManager _collectionManager;
        private readonly ILogger _logger;
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// The library manager.
        /// The collection manager.
        /// The logger.
        public CollectionPostScanTask(
            ILibraryManager libraryManager,
            ICollectionManager collectionManager,
            ILogger logger)
        {
            _libraryManager = libraryManager;
            _collectionManager = collectionManager;
            _logger = logger;
        }
        /// 
        /// Runs the specified progress.
        /// 
        /// The progress.
        /// The cancellation token.
        /// Task.
        public async Task Run(IProgress progress, CancellationToken cancellationToken)
        {
            var collectionNameMoviesMap = new Dictionary>();
            foreach (var library in _libraryManager.RootFolder.Children)
            {
                if (!_libraryManager.GetLibraryOptions(library).AutomaticallyAddToCollection)
                {
                    continue;
                }
                var startIndex = 0;
                var pagesize = 1000;
                while (true)
                {
                    var movies = _libraryManager.GetItemList(new InternalItemsQuery
                    {
                        MediaTypes = new string[] { MediaType.Video },
                        IncludeItemTypes = new[] { BaseItemKind.Movie },
                        IsVirtualItem = false,
                        OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
                        Parent = library,
                        StartIndex = startIndex,
                        Limit = pagesize,
                        Recursive = true
                    });
                    foreach (var m in movies)
                    {
                        if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName))
                        {
                            if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList))
                            {
                                movieList.Add(movie.Id);
                            }
                            else
                            {
                                collectionNameMoviesMap[movie.CollectionName] = new HashSet { movie.Id };
                            }
                        }
                    }
                    if (movies.Count < pagesize)
                    {
                        break;
                    }
                    startIndex += pagesize;
                }
            }
            var numComplete = 0;
            var count = collectionNameMoviesMap.Count;
            if (count == 0)
            {
                progress.Report(100);
                return;
            }
            var boxSets = _libraryManager.GetItemList(new InternalItemsQuery
            {
                IncludeItemTypes = new[] { BaseItemKind.BoxSet },
                CollapseBoxSetItems = false,
                Recursive = true
            });
            foreach (var (collectionName, movieIds) in collectionNameMoviesMap)
            {
                try
                {
                    var boxSet = boxSets.FirstOrDefault(b => b?.Name == collectionName) as BoxSet;
                    if (boxSet == null)
                    {
                        // won't automatically create collection if only one movie in it
                        if (movieIds.Count >= 2)
                        {
                            boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions
                            {
                                Name = collectionName,
                                IsLocked = true
                            });
                            await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds);
                        }
                    }
                    else
                    {
                        await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds);
                    }
                    numComplete++;
                    double percent = numComplete;
                    percent /= count;
                    percent *= 100;
                    progress.Report(percent);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error refreshing {CollectionName} with {@MovieIds}", collectionName, movieIds);
                }
            }
            progress.Report(100);
        }
    }
}