using MediaBrowser.Common.Implementations.HttpServer;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace MediaBrowser.Api.UserLibrary
{
    /// 
    /// Class BaseItemsByNameService
    /// 
    /// The type of the T item type.
    public abstract class BaseItemsByNameService : BaseRestService
        where TItemType : BaseItem
    {
        /// 
        /// The _user manager
        /// 
        protected readonly IUserManager UserManager;
        protected readonly ILibraryManager LibraryManager;
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// The user manager.
        protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager)
        {
            UserManager = userManager;
            LibraryManager = libraryManager;
        }
        /// 
        /// Gets the specified request.
        /// 
        /// The request.
        /// Task{ItemsResult}.
        protected async Task GetResult(GetItemsByName request)
        {
            var user = UserManager.GetUserById(request.UserId);
            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, UserManager, LibraryManager, user.Id);
            IEnumerable items;
            if (item.IsFolder)
            {
                var folder = (Folder)item;
                items = request.Recursive ? folder.GetRecursiveChildren(user) : folder.GetChildren(user);
            }
            else
            {
                items = new[] { item };
            }
            var ibnItemsArray = GetAllItems(request, items, user).ToArray();
            IEnumerable>> ibnItems = ibnItemsArray;
            var result = new ItemsResult
            {
                TotalRecordCount = ibnItemsArray.Length
            };
            if (request.StartIndex.HasValue || request.PageSize.HasValue)
            {
                if (request.StartIndex.HasValue)
                {
                    ibnItems = ibnItems.Skip(request.StartIndex.Value);
                }
                if (request.PageSize.HasValue)
                {
                    ibnItems = ibnItems.Take(request.PageSize.Value);
                }
            }
            var fields = GetItemFields(request).ToList();
            var tasks = ibnItems.Select(i => GetDto(i, user, fields));
            var resultItems = await Task.WhenAll(tasks).ConfigureAwait(false);
            result.Items = resultItems.Where(i => i != null).OrderByDescending(i => i.SortName ?? i.Name).ToArray();
            return result;
        }
        /// 
        /// Gets the item fields.
        /// 
        /// The request.
        /// IEnumerable{ItemFields}.
        private IEnumerable GetItemFields(GetItemsByName request)
        {
            var val = request.Fields;
            if (string.IsNullOrEmpty(val))
            {
                return new ItemFields[] { };
            }
            return val.Split(',').Select(v => (ItemFields)Enum.Parse(typeof(ItemFields), v, true));
        }
        /// 
        /// Gets all items.
        /// 
        /// The request.
        /// The items.
        /// The user.
        /// IEnumerable{Tuple{System.StringFunc{System.Int32}}}.
        protected abstract IEnumerable>> GetAllItems(GetItemsByName request, IEnumerable items, User user);
        /// 
        /// Gets the entity.
        /// 
        /// The name.
        /// Task{BaseItem}.
        protected abstract Task GetEntity(string name);
        /// 
        /// Gets the dto.
        /// 
        /// The stub.
        /// The user.
        /// The fields.
        /// Task{DtoBaseItem}.
        private async Task GetDto(Tuple> stub, User user, List fields)
        {
            BaseItem item;
            try
            {
                item = await GetEntity(stub.Item1).ConfigureAwait(false);
            }
            catch (IOException ex)
            {
                Logger.ErrorException("Error getting IBN item {0}", ex, stub.Item1);
                return null;
            }
            var dto = await new DtoBuilder(Logger).GetDtoBaseItem(item, user, fields, LibraryManager).ConfigureAwait(false);
            dto.ChildCount = stub.Item2();
            return dto;
        }
    }
    /// 
    /// Class GetItemsByName
    /// 
    public class GetItemsByName : IReturn
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the start index.
        /// 
        /// The start index.
        public int? StartIndex { get; set; }
        /// 
        /// Gets or sets the size of the page.
        /// 
        /// The size of the page.
        public int? PageSize { get; set; }
        /// 
        /// Gets or sets a value indicating whether this  is recursive.
        /// 
        /// true if recursive; otherwise, false.
        public bool Recursive { get; set; }
        /// 
        /// Gets or sets the sort order.
        /// 
        /// The sort order.
        public SortOrder? SortOrder { get; set; }
        /// 
        /// If specified the search will be localized within a specific item or folder
        /// 
        /// The item id.
        public string Id { get; set; }
        /// 
        /// Fields to return within the items, in addition to basic information
        /// 
        /// The fields.
        public string Fields { get; set; }
    }
}