using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Model.Logging;
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using MediaBrowser.Common.IO;
using System.Collections.Generic;
using CommonIO;

namespace MediaBrowser.Server.Startup.Common.FFMpeg
{
    public class FFmpegValidator
    {
        private readonly ILogger _logger;
        private readonly IApplicationPaths _appPaths;
        private readonly IFileSystem _fileSystem;

        public FFmpegValidator(ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem)
        {
            _logger = logger;
            _appPaths = appPaths;
            _fileSystem = fileSystem;
        }

        public Tuple<List<string>,List<string>> Validate(FFMpegInfo info)
        {
            _logger.Info("FFMpeg: {0}", info.EncoderPath);
            _logger.Info("FFProbe: {0}", info.ProbePath);

            var decoders = GetDecoders(info.EncoderPath);
            var encoders = GetEncoders(info.EncoderPath);

            return new Tuple<List<string>, List<string>>(decoders, encoders);
        }

        private List<string> GetDecoders(string ffmpegPath)
        {
            string output = string.Empty;
            try
            {
                output = GetFFMpegOutput(ffmpegPath, "-decoders");
            }
            catch
            {
            }

            var found = new List<string>();
            var required = new[]
            {
                "h264_qsv",
                "mpeg2_qsv",
                "vc1_qsv"
            };

            foreach (var codec in required)
            {
                var srch = " " + codec + "  ";

                if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1)
                {
                    _logger.Warn("ffmpeg is missing decoder " + codec);
                }
                else
                {
                    found.Add(codec);
                }
            }

            return found;
        }

        private List<string> GetEncoders(string ffmpegPath)
        {
            string output = null;
            try
            {
                output = GetFFMpegOutput(ffmpegPath, "-encoders");
            }
            catch
            {
            }

            var found = new List<string>();
            var required = new[]
            {
                "libx264",
                "libx265",
                "mpeg4",
                "msmpeg4",
                //"libvpx",
                //"libvpx-vp9",
                "aac",
                "ac3",
                "libmp3lame",
                //"libvorbis",
                "srt"
            };

            foreach (var codec in required)
            {
                var srch = " " + codec + "  ";

                if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1)
                {
                    _logger.Warn("ffmpeg is missing encoder " + codec);
                }
                else
                {
                    found.Add(codec);
                }
            }

            return found;
        }

        private string GetFFMpegOutput(string path, string arguments)
        {
            var process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    CreateNoWindow = true,
                    UseShellExecute = false,
                    FileName = path,
                    Arguments = arguments,
                    WindowStyle = ProcessWindowStyle.Hidden,
                    ErrorDialog = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true
                }
            };

            using (process)
            {
                process.Start();

                try
                {
                    process.BeginErrorReadLine();

                    using (var reader = new StreamReader(process.StandardOutput.BaseStream))
                    {
                        return reader.ReadToEnd();
                    }
                }
                catch
                {
                    // Hate having to do this
                    try
                    {
                        process.Kill();
                    }
                    catch (Exception ex1)
                    {
                        _logger.ErrorException("Error killing ffmpeg", ex1);
                    }

                    throw;
                }
            }
        }
    }
}
