using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Providers
{
    /// 
    /// Provides images for all types by looking for standard images - folder, backdrop, logo, etc.
    /// 
    public class ImageFromMediaLocationProvider : BaseMetadataProvider
    {
        public ImageFromMediaLocationProvider(ILogManager logManager, IServerConfigurationManager configurationManager)
            : base(logManager, configurationManager)
        {
        }
        public override ItemUpdateType ItemUpdateType
        {
            get
            {
                return ItemUpdateType.ImageUpdate;
            }
        }
        /// 
        /// Supportses the specified item.
        /// 
        /// The item.
        /// true if XXXX, false otherwise
        public override bool Supports(BaseItem item)
        {
            return item.LocationType == LocationType.FileSystem && item.ResolveArgs.IsDirectory;
        }
        /// 
        /// Gets the priority.
        /// 
        /// The priority.
        public override MetadataProviderPriority Priority
        {
            get { return MetadataProviderPriority.First; }
        }
        /// 
        /// Returns true or false indicating if the provider should refresh when the contents of it's directory changes
        /// 
        /// true if [refresh on file system stamp change]; otherwise, false.
        protected override bool RefreshOnFileSystemStampChange
        {
            get
            {
                return true;
            }
        }
        /// 
        /// Gets the filestamp extensions.
        /// 
        /// The filestamp extensions.
        protected override string[] FilestampExtensions
        {
            get
            {
                return BaseItem.SupportedImageExtensions;
            }
        }
        /// 
        /// Fetches metadata and returns true or false indicating if any work that requires persistence was done
        /// 
        /// The item.
        /// if set to true [force].
        /// The cancellation token.
        /// Task{System.Boolean}.
        public override Task FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            // Make sure current image paths still exist
            ValidateImages(item);
            cancellationToken.ThrowIfCancellationRequested();
            // Make sure current backdrop paths still exist
            ValidateBackdrops(item);
            cancellationToken.ThrowIfCancellationRequested();
            PopulateBaseItemImages(item);
            SetLastRefreshed(item, DateTime.UtcNow);
            return TrueTaskResult;
        }
        /// 
        /// Validates that images within the item are still on the file system
        /// 
        /// The item.
        private void ValidateImages(BaseItem item)
        {
            // Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
            var deletedKeys = item.Images.ToList().Where(image =>
            {
                var path = image.Value;
                return IsInMetaLocation(item, path) && item.ResolveArgs.GetMetaFileByPath(path) == null;
            }).Select(i => i.Key).ToList();
            // Now remove them from the dictionary
            foreach (var key in deletedKeys)
            {
                item.Images.Remove(key);
            }
        }
        /// 
        /// Validates that backdrops within the item are still on the file system
        /// 
        /// The item.
        private void ValidateBackdrops(BaseItem item)
        {
            if (item.BackdropImagePaths == null)
            {
                return;
            }
            // Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
            var deletedImages = item.BackdropImagePaths.Where(path => IsInMetaLocation(item, path) && item.ResolveArgs.GetMetaFileByPath(path) == null).ToList();
            // Now remove them from the dictionary
            foreach (var path in deletedImages)
            {
                item.BackdropImagePaths.Remove(path);
            }
        }
        /// 
        /// Determines whether [is in same directory] [the specified item].
        /// 
        /// The item.
        /// The path.
        /// true if [is in same directory] [the specified item]; otherwise, false.
        private bool IsInMetaLocation(BaseItem item, string path)
        {
            return string.Equals(Path.GetDirectoryName(path), item.MetaLocation, StringComparison.OrdinalIgnoreCase);
        }
        /// 
        /// Gets the image.
        /// 
        /// The item.
        /// The filename without extension.
        /// FileSystemInfo.
        protected virtual FileSystemInfo GetImage(BaseItem item, string filenameWithoutExtension)
        {
            return BaseItem.SupportedImageExtensions.Select(i => item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.ResolveArgs.Path, filenameWithoutExtension + i))).FirstOrDefault(i => i != null);
        }
        /// 
        /// Fills in image paths based on files win the folder
        /// 
        /// The item.
        private void PopulateBaseItemImages(BaseItem item)
        {
            // Primary Image
            var image = GetImage(item, "folder") ??
                GetImage(item, "poster") ??
                GetImage(item, "cover") ??
                GetImage(item, "default");
            // Look for a file with the same name as the item
            if (image == null)
            {
                var name = Path.GetFileNameWithoutExtension(item.Path);
                if (!string.IsNullOrEmpty(name))
                {
                    image = GetImage(item, name);
                }
            }
            if (image != null)
            {
                item.SetImage(ImageType.Primary, image.FullName);
            }
            // Logo Image
            image = GetImage(item, "logo");
            if (image != null)
            {
                item.SetImage(ImageType.Logo, image.FullName);
            }
            // Banner Image
            image = GetImage(item, "banner");
            if (image != null)
            {
                item.SetImage(ImageType.Banner, image.FullName);
            }
            // Clearart
            image = GetImage(item, "clearart");
            if (image != null)
            {
                item.SetImage(ImageType.Art, image.FullName);
            }
            // Disc
            image = GetImage(item, "disc");
            if (image != null)
            {
                item.SetImage(ImageType.Disc, image.FullName);
            }
            // Thumbnail Image
            image = GetImage(item, "thumb");
            if (image != null)
            {
                item.SetImage(ImageType.Thumb, image.FullName);
            }
            // Box Image
            image = GetImage(item, "box");
            if (image != null)
            {
                item.SetImage(ImageType.Box, image.FullName);
            }
            // BoxRear Image
            image = GetImage(item, "boxrear");
            if (image != null)
            {
                item.SetImage(ImageType.BoxRear, image.FullName);
            }
            // Thumbnail Image
            image = GetImage(item, "menu");
            if (image != null)
            {
                item.SetImage(ImageType.Menu, image.FullName);
            }
            // Backdrop Image
            PopulateBackdrops(item);
            // Screenshot Image
            image = GetImage(item, "screenshot");
            var screenshotFiles = new List();
            if (image != null)
            {
                screenshotFiles.Add(image.FullName);
            }
            var unfound = 0;
            for (var i = 1; i <= 20; i++)
            {
                // Screenshot Image
                image = GetImage(item, "screenshot" + i);
                if (image != null)
                {
                    screenshotFiles.Add(image.FullName);
                }
                else
                {
                    unfound++;
                    if (unfound >= 3)
                    {
                        break;
                    }
                }
            }
            if (screenshotFiles.Count > 0)
            {
                item.ScreenshotImagePaths = screenshotFiles;
            }
        }
        /// 
        /// Populates the backdrops.
        /// 
        /// The item.
        private void PopulateBackdrops(BaseItem item)
        {
            var backdropFiles = new List();
            PopulateBackdrops(item, backdropFiles, "backdrop", "backdrop");
            // Support plex/xbmc conventions
            PopulateBackdrops(item, backdropFiles, "fanart", "fanart-");
            PopulateBackdrops(item, backdropFiles, "background", "background-");
            if (backdropFiles.Count > 0)
            {
                item.BackdropImagePaths = backdropFiles;
            }
        }
        /// 
        /// Populates the backdrops.
        /// 
        /// The item.
        /// The backdrop files.
        /// The filename.
        /// The numbered suffix.
        private void PopulateBackdrops(BaseItem item, List backdropFiles, string filename, string numberedSuffix)
        {
            var image = GetImage(item, filename);
            if (image != null)
            {
                backdropFiles.Add(image.FullName);
            }
            var unfound = 0;
            for (var i = 1; i <= 20; i++)
            {
                // Backdrop Image
                image = GetImage(item, numberedSuffix + i);
                if (image != null)
                {
                    backdropFiles.Add(image.FullName);
                }
                else
                {
                    unfound++;
                    if (unfound >= 3)
                    {
                        break;
                    }
                }
            }
        }
    }
}