using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Api.UserLibrary
{
    /// 
    /// Class GetItem
    /// 
    [Route("/Users/{UserId}/Items/{Id}", "GET")]
    [Api(Description = "Gets an item from a user's library")]
    public class GetItem : IReturn
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
        public string Id { get; set; }
    }
    /// 
    /// Class GetItem
    /// 
    [Route("/Users/{UserId}/Items/Root", "GET")]
    [Api(Description = "Gets the root folder from a user's library")]
    public class GetRootFolder : IReturn
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
        public Guid UserId { get; set; }
    }
    /// 
    /// Class GetIntros
    /// 
    [Route("/Users/{UserId}/Items/{Id}/Intros", "GET")]
    [Api(("Gets intros to play before the main media item plays"))]
    public class GetIntros : IReturn>
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the item id.
        /// 
        /// The item id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
        public string Id { get; set; }
    }
    /// 
    /// Class MarkFavoriteItem
    /// 
    [Route("/Users/{UserId}/FavoriteItems/{Id}", "POST")]
    [Api(Description = "Marks an item as a favorite")]
    public class MarkFavoriteItem : IReturnVoid
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public string Id { get; set; }
    }
    /// 
    /// Class UnmarkFavoriteItem
    /// 
    [Route("/Users/{UserId}/FavoriteItems/{Id}", "DELETE")]
    [Api(Description = "Unmarks an item as a favorite")]
    public class UnmarkFavoriteItem : IReturnVoid
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
        public string Id { get; set; }
    }
    /// 
    /// Class ClearUserItemRating
    /// 
    [Route("/Users/{UserId}/Items/{Id}/Rating", "DELETE")]
    [Api(Description = "Deletes a user's saved personal rating for an item")]
    public class DeleteUserItemRating : IReturnVoid
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
        public string Id { get; set; }
    }
    /// 
    /// Class UpdateUserItemRating
    /// 
    [Route("/Users/{UserId}/Items/{Id}/Rating", "POST")]
    [Api(Description = "Updates a user's rating for an item")]
    public class UpdateUserItemRating : IReturnVoid
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public string Id { get; set; }
        /// 
        /// Gets or sets a value indicating whether this  is likes.
        /// 
        /// true if likes; otherwise, false.
        [ApiMember(Name = "Likes", Description = "Whether the user likes the item or not. true/false", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")]
        public bool Likes { get; set; }
    }
    /// 
    /// Class MarkPlayedItem
    /// 
    [Route("/Users/{UserId}/PlayedItems/{Id}", "POST")]
    [Api(Description = "Marks an item as played")]
    public class MarkPlayedItem : IReturnVoid
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public string Id { get; set; }
    }
    /// 
    /// Class MarkUnplayedItem
    /// 
    [Route("/Users/{UserId}/PlayedItems/{Id}", "DELETE")]
    [Api(Description = "Marks an item as unplayed")]
    public class MarkUnplayedItem : IReturnVoid
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
        public string Id { get; set; }
    }
    /// 
    /// Class OnPlaybackStart
    /// 
    [Route("/Users/{UserId}/PlayingItems/{Id}", "POST")]
    [Api(Description = "Reports that a user has begun playing an item")]
    public class OnPlaybackStart : IReturnVoid
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public string Id { get; set; }
    }
    /// 
    /// Class OnPlaybackProgress
    /// 
    [Route("/Users/{UserId}/PlayingItems/{Id}/Progress", "POST")]
    [Api(Description = "Reports a user's playback progress")]
    public class OnPlaybackProgress : IReturnVoid
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
        public string Id { get; set; }
        /// 
        /// Gets or sets the position ticks.
        /// 
        /// The position ticks.
        [ApiMember(Name = "PositionTicks", Description = "Optional. The current position, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
        public long? PositionTicks { get; set; }
        [ApiMember(Name = "IsPaused", Description = "Indicates if the player is paused.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
        public bool IsPaused { get; set; }
    }
    /// 
    /// Class OnPlaybackStopped
    /// 
    [Route("/Users/{UserId}/PlayingItems/{Id}", "DELETE")]
    [Api(Description = "Reports that a user has stopped playing an item")]
    public class OnPlaybackStopped : IReturnVoid
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
        public string Id { get; set; }
        /// 
        /// Gets or sets the position ticks.
        /// 
        /// The position ticks.
        [ApiMember(Name = "PositionTicks", Description = "Optional. The position, in ticks, where playback stopped. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "DELETE")]
        public long? PositionTicks { get; set; }
    }
    /// 
    /// Class GetLocalTrailers
    /// 
    [Route("/Users/{UserId}/Items/{Id}/LocalTrailers", "GET")]
    [Api(Description = "Gets local trailers for an item")]
    public class GetLocalTrailers : IReturn>
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
        public string Id { get; set; }
    }
    /// 
    /// Class GetSpecialFeatures
    /// 
    [Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET")]
    [Api(Description = "Gets special features for a movie")]
    public class GetSpecialFeatures : IReturn>
    {
        /// 
        /// Gets or sets the user id.
        /// 
        /// The user id.
        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
        public Guid UserId { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        [ApiMember(Name = "Id", Description = "Movie Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
        public string Id { get; set; }
    }
    /// 
    /// Class UserLibraryService
    /// 
    public class UserLibraryService : BaseApiService
    {
        /// 
        /// The _user manager
        /// 
        private readonly IUserManager _userManager;
        /// 
        /// The _user data repository
        /// 
        private readonly IUserDataRepository _userDataRepository;
        /// 
        /// The _library manager
        /// 
        private readonly ILibraryManager _libraryManager;
        private readonly IItemRepository _itemRepo;
        private readonly ISessionManager _sessionManager;
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// The user manager.
        /// The library manager.
        /// The user data repository.
        /// The item repo.
        /// jsonSerializer
        public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, ISessionManager sessionManager)
            : base()
        {
            _userManager = userManager;
            _libraryManager = libraryManager;
            _userDataRepository = userDataRepository;
            _itemRepo = itemRepo;
            _sessionManager = sessionManager;
        }
        /// 
        /// Gets the specified request.
        /// 
        /// The request.
        /// System.Object.
        public object Get(GetSpecialFeatures request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            // Get everything
            var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
            var movie = (Movie)item;
            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
            var items = movie.SpecialFeatureIds.Select(_itemRepo.RetrieveItem).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, fields, user)).Select(t => t.Result).ToList();
            return ToOptimizedResult(items);
        }
        /// 
        /// Gets the specified request.
        /// 
        /// The request.
        /// System.Object.
        public object Get(GetLocalTrailers request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            // Get everything
            var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
            var items = item.LocalTrailerIds.Select(_itemRepo.RetrieveItem).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, fields, user)).Select(t => t.Result).ToList();
            return ToOptimizedResult(items);
        }
        /// 
        /// Gets the specified request.
        /// 
        /// The request.
        /// System.Object.
        public object Get(GetItem request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            // Get everything
            var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
            var result = dtoBuilder.GetBaseItemDto(item, fields, user).Result;
            return ToOptimizedResult(result);
        }
        /// 
        /// Gets the specified request.
        /// 
        /// The request.
        /// System.Object.
        public object Get(GetRootFolder request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = user.RootFolder;
            // Get everything
            var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
            var result = dtoBuilder.GetBaseItemDto(item, fields, user).Result;
            return ToOptimizedResult(result);
        }
        /// 
        /// Gets the specified request.
        /// 
        /// The request.
        /// System.Object.
        public object Get(GetIntros request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            var result = _libraryManager.GetIntros(item, user);
            return ToOptimizedResult(result);
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        public void Post(MarkFavoriteItem request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            // Get the user data for this item
            var key = item.GetUserDataKey();
            var data = _userDataRepository.GetUserData(user.Id, key);
            // Set favorite status
            data.IsFavorite = true;
            var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None);
            Task.WaitAll(task);
        }
        /// 
        /// Deletes the specified request.
        /// 
        /// The request.
        public void Delete(UnmarkFavoriteItem request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            var key = item.GetUserDataKey();
            // Get the user data for this item
            var data = _userDataRepository.GetUserData(user.Id, key);
            // Set favorite status
            data.IsFavorite = false;
            var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None);
            Task.WaitAll(task);
        }
        /// 
        /// Deletes the specified request.
        /// 
        /// The request.
        public void Delete(DeleteUserItemRating request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            var key = item.GetUserDataKey();
            // Get the user data for this item
            var data = _userDataRepository.GetUserData(user.Id, key);
            data.Rating = null;
            var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None);
            Task.WaitAll(task);
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        public void Post(UpdateUserItemRating request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            var key = item.GetUserDataKey();
            // Get the user data for this item
            var data = _userDataRepository.GetUserData(user.Id, key);
            data.Likes = request.Likes;
            var task = _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None);
            Task.WaitAll(task);
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        public void Post(MarkPlayedItem request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var task = UpdatePlayedStatus(user, request.Id, true);
            Task.WaitAll(task);
        }
        private SessionInfo GetSession()
        {
            var auth = RequestFilterAttribute.GetAuthorization(RequestContext);
            string deviceId;
            string client;
            string version;
            auth.TryGetValue("DeviceId", out deviceId);
            auth.TryGetValue("Client", out client);
            auth.TryGetValue("Version", out version);
            version = version ?? "0.0.0.0";
            return _sessionManager.Sessions.First(i => string.Equals(i.DeviceId, deviceId) &&
                string.Equals(i.Client, client) &&
                string.Equals(i.ApplicationVersion, version));
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        public void Post(OnPlaybackStart request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            _sessionManager.OnPlaybackStart(item, GetSession().Id);
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        public void Post(OnPlaybackProgress request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            var task = _sessionManager.OnPlaybackProgress(item, request.PositionTicks, request.IsPaused, GetSession().Id);
            Task.WaitAll(task);
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        public void Delete(OnPlaybackStopped request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
            var task = _sessionManager.OnPlaybackStopped(item, request.PositionTicks, GetSession().Id);
            Task.WaitAll(task);
        }
        /// 
        /// Deletes the specified request.
        /// 
        /// The request.
        public void Delete(MarkUnplayedItem request)
        {
            var user = _userManager.GetUserById(request.UserId);
            var task = UpdatePlayedStatus(user, request.Id, false);
            Task.WaitAll(task);
        }
        /// 
        /// Updates the played status.
        /// 
        /// The user.
        /// The item id.
        /// if set to true [was played].
        /// Task.
        private Task UpdatePlayedStatus(User user, string itemId, bool wasPlayed)
        {
            var item = DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id);
            return item.SetPlayedStatus(user, wasPlayed, _userDataRepository);
        }
    }
}