#pragma warning disable CS1591

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;

namespace MediaBrowser.Providers.MediaInfo
{
    public class SubtitleResolver
    {
        private readonly ILocalizationManager _localization;

        private static readonly HashSet<string> SubtitleExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            ".srt",
            ".ssa",
            ".ass",
            ".sub",
            ".smi",
            ".sami",
            ".vtt"
        };

        public SubtitleResolver(ILocalizationManager localization)
        {
            _localization = localization;
        }

        public List<MediaStream> GetExternalSubtitleStreams(
            Video video,
            int startIndex,
            IDirectoryService directoryService,
            bool clearCache)
        {
            var streams = new List<MediaStream>();

            if (!video.IsFileProtocol)
            {
                return streams;
            }

            AddExternalSubtitleStreams(streams, video.ContainingFolderPath, video.Path, startIndex, directoryService, clearCache);

            startIndex += streams.Count;

            string folder = video.GetInternalMetadataPath();

            if (!Directory.Exists(folder))
            {
                return streams;
            }

            try
            {
                AddExternalSubtitleStreams(streams, folder, video.Path, startIndex, directoryService, clearCache);
            }
            catch (IOException)
            {
            }

            return streams;
        }

        public List<string> GetExternalSubtitleFiles(
            Video video,
            IDirectoryService directoryService,
            bool clearCache)
        {
            var list = new List<string>();

            if (!video.IsFileProtocol)
            {
                return list;
            }

            var streams = GetExternalSubtitleStreams(video, 0, directoryService, clearCache);

            foreach (var stream in streams)
            {
                list.Add(stream.Path);
            }

            return list;
        }

        private void AddExternalSubtitleStreams(
            List<MediaStream> streams,
            string folder,
            string videoPath,
            int startIndex,
            IDirectoryService directoryService,
            bool clearCache)
        {
            var files = directoryService.GetFilePaths(folder, clearCache).OrderBy(i => i).ToArray();

            AddExternalSubtitleStreams(streams, videoPath, startIndex, files);
        }

        public void AddExternalSubtitleStreams(
            List<MediaStream> streams,
            string videoPath,
            int startIndex,
            string[] files)
        {
            var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(videoPath);
            videoFileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(videoFileNameWithoutExtension);

            foreach (var fullName in files)
            {
                var extension = Path.GetExtension(fullName);

                if (!SubtitleExtensions.Contains(extension))
                {
                    continue;
                }

                var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName);
                fileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(fileNameWithoutExtension);

                if (!string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) &&
                    !fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                var codec = Path.GetExtension(fullName).ToLowerInvariant().TrimStart('.');

                if (string.Equals(codec, "txt", StringComparison.OrdinalIgnoreCase))
                {
                    codec = "srt";
                }

                // If the subtitle file matches the video file name
                if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
                {
                    streams.Add(new MediaStream
                    {
                        Index = startIndex++,
                        Type = MediaStreamType.Subtitle,
                        IsExternal = true,
                        Path = fullName,
                        Codec = codec
                    });
                }
                else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
                {
                    var isForced = fullName.IndexOf(".forced.", StringComparison.OrdinalIgnoreCase) != -1 ||
                        fullName.IndexOf(".foreign.", StringComparison.OrdinalIgnoreCase) != -1;

                    var isDefault = fullName.IndexOf(".default.", StringComparison.OrdinalIgnoreCase) != -1;

                    // Support xbmc naming conventions - 300.spanish.srt
                    var language = fileNameWithoutExtension
                        .Replace(".forced", string.Empty, StringComparison.OrdinalIgnoreCase)
                        .Replace(".foreign", string.Empty, StringComparison.OrdinalIgnoreCase)
                        .Replace(".default", string.Empty, StringComparison.OrdinalIgnoreCase)
                        .Split('.')
                        .LastOrDefault();

                    // Try to translate to three character code
                    // Be flexible and check against both the full and three character versions
                    var culture = _localization.FindLanguageInfo(language);

                    if (culture != null)
                    {
                        language = culture.ThreeLetterISOLanguageName;
                    }

                    streams.Add(new MediaStream
                    {
                        Index = startIndex++,
                        Type = MediaStreamType.Subtitle,
                        IsExternal = true,
                        Path = fullName,
                        Codec = codec,
                        Language = language,
                        IsForced = isForced,
                        IsDefault = isDefault
                    });
                }
            }
        }

        private string NormalizeFilenameForSubtitleComparison(string filename)
        {
            // Try to account for sloppy file naming
            filename = filename.Replace("_", string.Empty, StringComparison.Ordinal);
            filename = filename.Replace(" ", string.Empty, StringComparison.Ordinal);

            // can't normalize this due to languages such as pt-br
            // filename = filename.Replace("-", string.Empty);

            // filename = filename.Replace(".", string.Empty);

            return filename;
        }
    }
}