using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
namespace MediaBrowser.Controller.Providers
{
    /// 
    /// Provides images for all types by looking for standard images - folder, backdrop, logo, etc.
    /// 
    public class ImageFromMediaLocationProvider : BaseMetadataProvider
    {
        public ImageFromMediaLocationProvider(ILogManager logManager) : base(logManager)
        {
        }
        /// 
        /// Supportses the specified item.
        /// 
        /// The item.
        /// true if XXXX, false otherwise
        public override bool Supports(BaseItem item)
        {
            return item.ResolveArgs.IsDirectory && item.LocationType == LocationType.FileSystem;
        }
        /// 
        /// 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;
            }
        }
        /// 
        /// 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}.
        protected override Task FetchAsyncInternal(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)
        {
            if (item.Images == 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 deletedKeys = item.Images.Keys.Where(image =>
            {
                var path = item.Images[image];
                return IsInSameDirectory(item, path) && !item.ResolveArgs.GetMetaFileByPath(path).HasValue;
            }).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 => IsInSameDirectory(item, path) && !item.ResolveArgs.GetMetaFileByPath(path).HasValue).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 IsInSameDirectory(BaseItem item, string path)
        {
            return string.Equals(Path.GetDirectoryName(path), item.Path, StringComparison.OrdinalIgnoreCase);
        }
        /// 
        /// Gets the image.
        /// 
        /// The item.
        /// The filename without extension.
        /// System.Nullable{WIN32_FIND_DATA}.
        protected virtual WIN32_FIND_DATA? GetImage(BaseItem item, string filenameWithoutExtension)
        {
            return item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.ResolveArgs.Path, filenameWithoutExtension + ".png")) ?? item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.ResolveArgs.Path, filenameWithoutExtension + ".jpg"));
        }
        /// 
        /// Fills in image paths based on files win the folder
        /// 
        /// The item.
        private void PopulateBaseItemImages(BaseItem item)
        {
            var backdropFiles = new List();
            // Primary Image
            var image = GetImage(item, "folder");
            if (image.HasValue)
            {
                item.SetImage(ImageType.Primary, image.Value.Path);
            }
            // Logo Image
            image = GetImage(item, "logo");
            if (image.HasValue)
            {
                item.SetImage(ImageType.Logo, image.Value.Path);
            }
            // Banner Image
            image = GetImage(item, "banner");
            if (image.HasValue)
            {
                item.SetImage(ImageType.Banner, image.Value.Path);
            }
            // Clearart
            image = GetImage(item, "clearart");
            if (image.HasValue)
            {
                item.SetImage(ImageType.Art, image.Value.Path);
            }
            // Thumbnail Image
            image = GetImage(item, "thumb");
            if (image.HasValue)
            {
                item.SetImage(ImageType.Thumb, image.Value.Path);
            }
            // Backdrop Image
            image = GetImage(item, "backdrop");
            if (image.HasValue)
            {
                backdropFiles.Add(image.Value.Path);
            }
            var unfound = 0;
            for (var i = 1; i <= 20; i++)
            {
                // Backdrop Image
                image = GetImage(item, "backdrop" + i);
                if (image.HasValue)
                {
                    backdropFiles.Add(image.Value.Path);
                }
                else
                {
                    unfound++;
                    if (unfound >= 3)
                    {
                        break;
                    }
                }
            }
            if (backdropFiles.Count > 0)
            {
                item.BackdropImagePaths = backdropFiles;
            }
        }
    }
}