using System;
using System.IO;
using MediaInfoLib;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Model;

namespace NzbDrone.Core.Providers
{
    public interface IVideoFileInfoReader
    {
        MediaInfoModel GetMediaInfo(string filename);
        TimeSpan GetRunTime(string filename);
    }

    public class VideoFileInfoReader : IVideoFileInfoReader
    {
        private readonly IDiskProvider _diskProvider;
        private readonly Logger _logger;


        public VideoFileInfoReader(IDiskProvider diskProvider, Logger logger)
        {
            _diskProvider = diskProvider;
            _logger = logger;
        }


        public MediaInfoModel GetMediaInfo(string filename)
        {
            if (!_diskProvider.FileExists(filename))
                throw new FileNotFoundException("Media file does not exist: " + filename);

            var mediaInfo = new MediaInfo();

            try
            {
                _logger.Trace("Getting media info from {0}", filename);

                mediaInfo.Option("ParseSpeed", "0.2");
                int open = mediaInfo.Open(filename);

                if (open != 0)
                {
                    int width;
                    int height;
                    int videoBitRate;
                    int audioBitRate;
                    int runTime;
                    int streamCount;
                    int audioChannels;

                    string subtitles = mediaInfo.Get(StreamKind.General, 0, "Text_Language_List");
                    string scanType = mediaInfo.Get(StreamKind.Video, 0, "ScanType");
                    Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "Width"), out width);
                    Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "Height"), out height);
                    Int32.TryParse(mediaInfo.Get(StreamKind.Video, 0, "BitRate"), out videoBitRate);

                    string aBitRate = mediaInfo.Get(StreamKind.Audio, 0, "BitRate");
                    int ABindex = aBitRate.IndexOf(" /");
                    if (ABindex > 0)
                        aBitRate = aBitRate.Remove(ABindex);

                    Int32.TryParse(aBitRate, out audioBitRate);
                    Int32.TryParse(mediaInfo.Get(StreamKind.General, 0, "PlayTime"), out runTime);
                    Int32.TryParse(mediaInfo.Get(StreamKind.Audio, 0, "StreamCount"), out streamCount);

                    string audioChannelsStr = mediaInfo.Get(StreamKind.Audio, 0, "Channel(s)");
                    int ACindex = audioChannelsStr.IndexOf(" /");
                    if (ACindex > 0)
                        audioChannelsStr = audioChannelsStr.Remove(ACindex);

                    string audioLanguages = mediaInfo.Get(StreamKind.General, 0, "Audio_Language_List");
                    decimal videoFrameRate = Decimal.Parse(mediaInfo.Get(StreamKind.Video, 0, "FrameRate"));
                    string audioProfile = mediaInfo.Get(StreamKind.Audio, 0, "Format_Profile");

                    int APindex = audioProfile.IndexOf(" /");
                    if (APindex > 0)
                        audioProfile = audioProfile.Remove(APindex);

                    Int32.TryParse(audioChannelsStr, out audioChannels);
                    var mediaInfoModel = new MediaInfoModel
                                                {
                                                    VideoCodec = mediaInfo.Get(StreamKind.Video, 0, "Codec/String"),
                                                    VideoBitrate = videoBitRate,
                                                    Height = height,
                                                    Width = width,
                                                    AudioFormat = mediaInfo.Get(StreamKind.Audio, 0, "Format"),
                                                    AudioBitrate = audioBitRate,
                                                    RunTime = (runTime / 1000), //InSeconds
                                                    AudioStreamCount = streamCount,
                                                    AudioChannels = audioChannels,
                                                    AudioProfile = audioProfile.Trim(),
                                                    VideoFps = videoFrameRate,
                                                    AudioLanguages = audioLanguages,
                                                    Subtitles = subtitles,
                                                    ScanType = scanType
                                                };

                    mediaInfo.Close();
                    return mediaInfoModel;
                }
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Unable to parse media info from file: " + filename, ex);
                mediaInfo.Close();
            }

            return null;
        }

        public TimeSpan GetRunTime(string filename)
        {
            var mediaInfo = new MediaInfo();

            try
            {
                _logger.Trace("Getting media info from {0}", filename);

                mediaInfo.Option("ParseSpeed", "0.2");
                int open = mediaInfo.Open(filename);

                if (open != 0)
                {
                    int runTime;
                    Int32.TryParse(mediaInfo.Get(StreamKind.General, 0, "PlayTime"), out runTime);

                    mediaInfo.Close();
                    return TimeSpan.FromMilliseconds(runTime);
                }
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Unable to parse media info from file: " + filename, ex);
                mediaInfo.Close();
            }

            return new TimeSpan();
        }
    }
}
