using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Persistence;
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.Controller.MediaInfo
{
    /// 
    /// Class FFMpegManager
    /// 
    public class FFMpegManager
    {
        /// 
        /// Gets or sets the video image cache.
        /// 
        /// The video image cache.
        internal FileSystemRepository VideoImageCache { get; set; }
        /// 
        /// Gets or sets the subtitle cache.
        /// 
        /// The subtitle cache.
        internal FileSystemRepository SubtitleCache { get; set; }
        private readonly IServerApplicationPaths _appPaths;
        private readonly IMediaEncoder _encoder;
        private readonly ILogger _logger;
        private readonly IItemRepository _itemRepo;
        private readonly IFileSystem _fileSystem;
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// The app paths.
        /// The encoder.
        /// The logger.
        /// The item repo.
        /// zipClient
        public FFMpegManager(IServerApplicationPaths appPaths, IMediaEncoder encoder, ILogger logger, IItemRepository itemRepo, IFileSystem fileSystem)
        {
            _appPaths = appPaths;
            _encoder = encoder;
            _logger = logger;
            _itemRepo = itemRepo;
            _fileSystem = fileSystem;
            VideoImageCache = new FileSystemRepository(VideoImagesDataPath);
            SubtitleCache = new FileSystemRepository(SubtitleCachePath);
        }
        /// 
        /// Gets the video images data path.
        /// 
        /// The video images data path.
        public string VideoImagesDataPath
        {
            get
            {
                return Path.Combine(_appPaths.DataPath, "extracted-video-images");
            }
        }
        /// 
        /// Gets the audio images data path.
        /// 
        /// The audio images data path.
        public string AudioImagesDataPath
        {
            get
            {
                return Path.Combine(_appPaths.DataPath, "extracted-audio-images");
            }
        }
        /// 
        /// Gets the subtitle cache path.
        /// 
        /// The subtitle cache path.
        public string SubtitleCachePath
        {
            get
            {
                return Path.Combine(_appPaths.CachePath, "subtitles");
            }
        }
        
        /// 
        /// The first chapter ticks
        /// 
        private static readonly long FirstChapterTicks = TimeSpan.FromSeconds(15).Ticks;
        /// 
        /// Extracts the chapter images.
        /// 
        /// The video.
        /// The chapters.
        /// if set to true [extract images].
        /// if set to true [save chapters].
        /// The cancellation token.
        /// Task.
        /// 
        public async Task PopulateChapterImages(Video video, List chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken)
        {
            // Can't extract images if there are no video streams
            if (video.MediaStreams == null || video.MediaStreams.All(m => m.Type != MediaStreamType.Video))
            {
                return true;
            }
            var success = true;
            var changesMade = false;
            var runtimeTicks = video.RunTimeTicks ?? 0;
            foreach (var chapter in chapters)
            {
                if (chapter.StartPositionTicks >= runtimeTicks)
                {
                    _logger.Info("Stopping chapter extraction for {0} because a chapter was found with a position greater than the runtime.", video.Name);
                    break;
                }
                var filename = video.Path + "_" + video.DateModified.Ticks + "_" + chapter.StartPositionTicks;
                var path = VideoImageCache.GetResourcePath(filename, ".jpg");
                if (!File.Exists(path))
                {
                    if (extractImages)
                    {
                        if (video.VideoType == VideoType.HdDvd || video.VideoType == VideoType.Iso)
                        {
                            continue;
                        }
                        if (video.VideoType == VideoType.BluRay)
                        {
                            // Can only extract reliably on single file blurays
                            if (video.PlayableStreamFileNames == null || video.PlayableStreamFileNames.Count != 1)
                            {
                                continue;
                            }
                        }
                        // Add some time for the first chapter to make sure we don't end up with a black image
                        var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(FirstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks);
                        InputType type;
                        var inputPath = MediaEncoderHelpers.GetInputArgument(video, null, out type);
                        try
                        {
                            var parentPath = Path.GetDirectoryName(path);
                            Directory.CreateDirectory(parentPath);
                            
                            await _encoder.ExtractImage(inputPath, type, video.Video3DFormat, time, path, cancellationToken).ConfigureAwait(false);
                            chapter.ImagePath = path;
                            changesMade = true;
                        }
                        catch
                        {
                            success = false;
                            break;
                        }
                    }
                }
                else if (!string.Equals(path, chapter.ImagePath, StringComparison.OrdinalIgnoreCase))
                {
                    chapter.ImagePath = path;
                    changesMade = true;
                }
            }
            if (saveChapters && changesMade)
            {
                await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false);
            }
            return success;
        }
        /// 
        /// Gets the subtitle cache path.
        /// 
        /// The input.
        /// Index of the subtitle stream.
        /// The offset.
        /// The output extension.
        /// System.String.
        public string GetSubtitleCachePath(Video input, int subtitleStreamIndex, TimeSpan? offset, string outputExtension)
        {
            var ticksParam = offset.HasValue ? "_" + offset.Value.Ticks : "";
            var stream = input.MediaStreams[subtitleStreamIndex];
            if (stream.IsExternal)
            {
                ticksParam += _fileSystem.GetLastWriteTimeUtc(stream.Path).Ticks;
            }
            return SubtitleCache.GetResourcePath(input.Id + "_" + subtitleStreamIndex + "_" + input.DateModified.Ticks + ticksParam, outputExtension);
        }
    }
}