using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Serialization;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.DTO;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using ServiceStack.Text.Controller;
namespace MediaBrowser.Api
{
    /// 
    /// Class GetUsers
    /// 
    [Route("/Users", "GET")]
    public class GetUsers : IReturn>
    {
    }
    /// 
    /// Class GetUser
    /// 
    [Route("/Users/{Id}", "GET")]
    public class GetUser : IReturn
    {
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        public Guid Id { get; set; }
    }
    /// 
    /// Class DeleteUser
    /// 
    [Route("/Users/{Id}", "DELETE")]
    public class DeleteUser : IReturnVoid
    {
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        public Guid Id { get; set; }
    }
    /// 
    /// Class AuthenticateUser
    /// 
    [Route("/Users/{Id}/Authenticate", "POST")]
    public class AuthenticateUser : IReturnVoid
    {
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        public Guid Id { get; set; }
        /// 
        /// Gets or sets the password.
        /// 
        /// The password.
        public string Password { get; set; }
    }
    /// 
    /// Class UpdateUserPassword
    /// 
    [Route("/Users/{Id}/Password", "POST")]
    public class UpdateUserPassword : IReturnVoid
    {
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        public Guid Id { get; set; }
        /// 
        /// Gets or sets the password.
        /// 
        /// The password.
        public string CurrentPassword { get; set; }
        /// 
        /// Gets or sets the new password.
        /// 
        /// The new password.
        public string NewPassword { get; set; }
        /// 
        /// Gets or sets a value indicating whether [reset password].
        /// 
        /// true if [reset password]; otherwise, false.
        public bool ResetPassword { get; set; }
    }
    /// 
    /// Class UpdateUser
    /// 
    [Route("/Users/{Id}", "POST")]
    public class UpdateUser : IRequiresRequestStream, IReturnVoid
    {
        /// 
        /// The raw Http Request Input Stream
        /// 
        /// The request stream.
        public Stream RequestStream { get; set; }
        /// 
        /// Gets or sets the id.
        /// 
        /// The id.
        public Guid Id { get; set; }
    }
    /// 
    /// Class CreateUser
    /// 
    [Route("/Users", "POST")]
    public class CreateUser : IRequiresRequestStream, IReturn
    {
        /// 
        /// The raw Http Request Input Stream
        /// 
        /// The request stream.
        public Stream RequestStream { get; set; }
    }
    /// 
    /// Class UsersService
    /// 
    [Export(typeof(IRestfulService))]
    public class UserService : BaseRestService
    {
        /// 
        /// Gets the specified request.
        /// 
        /// The request.
        /// System.Object.
        public object Get(GetUsers request)
        {
            var kernel = (Kernel)Kernel;
            var result = kernel.Users.OrderBy(u => u.Name).Select(DtoBuilder.GetDtoUser).ToList();
            return ToOptimizedResult(result);
        }
        /// 
        /// Gets the specified request.
        /// 
        /// The request.
        /// System.Object.
        public object Get(GetUser request)
        {
            var kernel = (Kernel)Kernel;
            var user = kernel.GetUserById(request.Id);
            if (user == null)
            {
                throw new ResourceNotFoundException("User not found");
            }
            var result = DtoBuilder.GetDtoUser(user);
            return ToOptimizedResult(result);
        }
        /// 
        /// Deletes the specified request.
        /// 
        /// The request.
        public void Delete(DeleteUser request)
        {
            var kernel = (Kernel)Kernel;
            var user = kernel.GetUserById(request.Id);
            if (user == null)
            {
                throw new ResourceNotFoundException("User not found");
            }
            var task = kernel.UserManager.DeleteUser(user);
            Task.WaitAll(task);
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        public void Post(AuthenticateUser request)
        {
            var kernel = (Kernel)Kernel;
            var user = kernel.GetUserById(request.Id);
            if (user == null)
            {
                throw new ResourceNotFoundException("User not found");
            }
            var success = kernel.UserManager.AuthenticateUser(user, request.Password).Result;
            if (!success)
            {
                // Unauthorized
                throw new ResourceNotFoundException("Invalid user or password entered.");
            }
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        public void Post(UpdateUserPassword request)
        {
            var kernel = (Kernel)Kernel;
            var user = kernel.GetUserById(request.Id);
            if (user == null)
            {
                throw new ResourceNotFoundException("User not found");
            }
            if (request.ResetPassword)
            {
                var task = user.ResetPassword();
                Task.WaitAll(task);
            }
            else
            {
                var success = kernel.UserManager.AuthenticateUser(user, request.CurrentPassword).Result;
                if (!success)
                {
                    throw new ResourceNotFoundException("Invalid user or password entered.");
                }
                var task = user.ChangePassword(request.NewPassword);
                Task.WaitAll(task);
            }
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        public void Post(UpdateUser request)
        {
            // We need to parse this manually because we told service stack not to with IRequiresRequestStream
            // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
            var pathInfo = PathInfo.Parse(Request.PathInfo);
            var id = new Guid(pathInfo.GetArgumentValue(1));
            
            var kernel = (Kernel)Kernel;
            var dtoUser = JsonSerializer.DeserializeFromStream(request.RequestStream);
            var user = kernel.GetUserById(id);
            var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ? kernel.UserManager.UpdateUser(user) : kernel.UserManager.RenameUser(user, dtoUser.Name);
            Task.WaitAll(task);
            user.UpdateConfiguration(dtoUser.Configuration);
        }
        /// 
        /// Posts the specified request.
        /// 
        /// The request.
        /// System.Object.
        public object Post(CreateUser request)
        {
            var kernel = (Kernel)Kernel;
            var dtoUser = JsonSerializer.DeserializeFromStream(request.RequestStream);
            var newUser = kernel.UserManager.CreateUser(dtoUser.Name).Result;
            var result = DtoBuilder.GetDtoUser(newUser);
            return ToOptimizedResult(result);
        }
    }
}