using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
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 = [MediaType.Video],
                    IncludeItemTypes = [BaseItemKind.Movie],
                    IsVirtualItem = false,
                    OrderBy = [(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 = [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 is null)
                {
                    // won't automatically create collection if only one movie in it
                    if (movieIds.Count >= 2)
                    {
                        boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions
                        {
                            Name = collectionName,
                        }).ConfigureAwait(false);
                        await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds).ConfigureAwait(false);
                    }
                }
                else
                {
                    await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds).ConfigureAwait(false);
                }
                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);
    }
}