using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using System;
using System.IO;
using System.Linq;
namespace MediaBrowser.Api.Library
{
    /// 
    /// Class LibraryHelpers
    /// 
    public static class LibraryHelpers
    {
        /// 
        /// Adds the virtual folder.
        /// 
        /// The name.
        /// The user.
        /// The app paths.
        /// There is already a media collection with the name  + name + .
        public static void AddVirtualFolder(string name, User user, IServerApplicationPaths appPaths)
        {
            name = FileSystem.GetValidFilename(name);
            var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
            var virtualFolderPath = Path.Combine(rootFolderPath, name);
            if (Directory.Exists(virtualFolderPath))
            {
                throw new ArgumentException("There is already a media collection with the name " + name + ".");
            }
            Directory.CreateDirectory(virtualFolderPath);
        }
        /// 
        /// Removes the virtual folder.
        /// 
        /// The name.
        /// The user.
        /// The app paths.
        /// The media folder does not exist
        public static void RemoveVirtualFolder(string name, User user, IServerApplicationPaths appPaths)
        {
            var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
            var path = Path.Combine(rootFolderPath, name);
            if (!Directory.Exists(path))
            {
                throw new DirectoryNotFoundException("The media folder does not exist");
            }
            Directory.Delete(path, true);
        }
        /// 
        /// Renames the virtual folder.
        /// 
        /// The name.
        /// The new name.
        /// The user.
        /// The app paths.
        /// The media collection does not exist
        /// There is already a media collection with the name  + newPath + .
        public static void RenameVirtualFolder(string name, string newName, User user, IServerApplicationPaths appPaths)
        {
            var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
            var currentPath = Path.Combine(rootFolderPath, name);
            var newPath = Path.Combine(rootFolderPath, newName);
            if (!Directory.Exists(currentPath))
            {
                throw new DirectoryNotFoundException("The media collection does not exist");
            }
            if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && Directory.Exists(newPath))
            {
                throw new ArgumentException("There is already a media collection with the name " + newPath + ".");
            }
            //Only make a two-phase move when changing capitalization
            if (string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase))
            {
                //Create an unique name
                var temporaryName = Guid.NewGuid().ToString();
                var temporaryPath = Path.Combine(rootFolderPath, temporaryName);
                Directory.Move(currentPath,temporaryPath);
                currentPath = temporaryPath;
            }
            Directory.Move(currentPath, newPath);
        }
        /// 
        /// Deletes a shortcut from within a virtual folder, within either the default view or a user view
        /// 
        /// Name of the virtual folder.
        /// The media path.
        /// The user.
        /// The app paths.
        /// The media folder does not exist
        public static void RemoveMediaPath(string virtualFolderName, string mediaPath, User user, IServerApplicationPaths appPaths)
        {
            var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
            var path = Path.Combine(rootFolderPath, virtualFolderName);
            if (!Directory.Exists(path))
            {
                throw new DirectoryNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName));
            }
            var shortcut = Directory.EnumerateFiles(path, "*.lnk", SearchOption.AllDirectories).FirstOrDefault(f => FileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
            if (!string.IsNullOrEmpty(shortcut))
            {
                File.Delete(shortcut);
            }
        }
        /// 
        /// Adds an additional mediaPath to an existing virtual folder, within either the default view or a user view
        /// 
        /// Name of the virtual folder.
        /// The path.
        /// The user.
        /// The app paths.
        /// The path is not valid.
        /// The path does not exist.
        public static void AddMediaPath(string virtualFolderName, string path, User user, IServerApplicationPaths appPaths)
        {
            if (!Path.IsPathRooted(path))
            {
                throw new ArgumentException("The path is not valid.");
            }
            if (!Directory.Exists(path))
            {
                throw new DirectoryNotFoundException("The path does not exist.");
            }
            // Strip off trailing slash, but not on drives
            path = path.TrimEnd(Path.DirectorySeparatorChar);
            if (path.EndsWith(":", StringComparison.OrdinalIgnoreCase))
            {
                path += Path.DirectorySeparatorChar;
            }
            var rootFolderPath = user != null ? user.RootFolderPath : appPaths.DefaultUserViewsPath;
            var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
            ValidateNewMediaPath(rootFolderPath, path, appPaths);
            var shortcutFilename = Path.GetFileNameWithoutExtension(path);
            var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ".lnk");
            while (File.Exists(lnk))
            {
                shortcutFilename += "1";
                lnk = Path.Combine(virtualFolderPath, shortcutFilename + ".lnk");
            }
            FileSystem.CreateShortcut(lnk, path);
        }
        /// 
        /// Validates that a new media path can be added
        /// 
        /// The current view root folder path.
        /// The media path.
        /// The app paths.
        /// 
        private static void ValidateNewMediaPath(string currentViewRootFolderPath, string mediaPath, IServerApplicationPaths appPaths)
        {
            var duplicate = Directory.EnumerateFiles(appPaths.RootFolderPath, "*.lnk", SearchOption.AllDirectories)
                .Select(FileSystem.ResolveShortcut)
                .FirstOrDefault(p => !IsNewPathValid(mediaPath, p, false));
            if (!string.IsNullOrEmpty(duplicate))
            {
                throw new ArgumentException(string.Format("The path cannot be added to the library because {0} already exists.", duplicate));
            }
            // Don't allow duplicate sub-paths within the same user library, or it will result in duplicate items
            // See comments in IsNewPathValid
            duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, "*.lnk", SearchOption.AllDirectories)
              .Select(FileSystem.ResolveShortcut)
              .FirstOrDefault(p => !IsNewPathValid(mediaPath, p, true));
            if (!string.IsNullOrEmpty(duplicate))
            {
                throw new ArgumentException(string.Format("The path cannot be added to the library because {0} already exists.", duplicate));
            }
            
            // Make sure the current root folder doesn't already have a shortcut to the same path
            duplicate = Directory.EnumerateFiles(currentViewRootFolderPath, "*.lnk", SearchOption.AllDirectories)
                .Select(FileSystem.ResolveShortcut)
                .FirstOrDefault(p => mediaPath.Equals(p, StringComparison.OrdinalIgnoreCase));
            if (!string.IsNullOrEmpty(duplicate))
            {
                throw new ArgumentException(string.Format("The path {0} already exists in the library", mediaPath));
            }
        }
        /// 
        /// Validates that a new path can be added based on an existing path
        /// 
        /// The new path.
        /// The existing path.
        /// if set to true [enforce sub path restriction].
        /// true if [is new path valid] [the specified new path]; otherwise, false.
        private static bool IsNewPathValid(string newPath, string existingPath, bool enforceSubPathRestriction)
        {
            // Example: D:\Movies is the existing path
            // D:\ cannot be added
            // Neither can D:\Movies\Kids
            // A D:\Movies duplicate is ok here since that will be caught later
            if (newPath.Equals(existingPath, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }
            // If enforceSubPathRestriction is true, validate the D:\Movies\Kids scenario
            if (enforceSubPathRestriction && newPath.StartsWith(existingPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
            {
                return false;
            }
            // Validate the D:\ scenario
            if (existingPath.StartsWith(newPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
            {
                return false;
            }
            return true;
        }
    }
}