using System;
using System.IO;
using System.Linq;
using Emby.Naming.Common;
using Jellyfin.Extensions;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
namespace Emby.Naming.ExternalFiles
{
    /// 
    /// External media file parser class.
    /// 
    public class ExternalPathParser
    {
        private readonly NamingOptions _namingOptions;
        private readonly DlnaProfileType _type;
        private readonly ILocalizationManager _localizationManager;
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// The localization manager.
        /// The  object containing FileExtensions, MediaDefaultFlags, MediaForcedFlags and MediaFlagDelimiters.
        /// The  of the parsed file.
        public ExternalPathParser(NamingOptions namingOptions, ILocalizationManager localizationManager, DlnaProfileType type)
        {
            _localizationManager = localizationManager;
            _namingOptions = namingOptions;
            _type = type;
        }
        /// 
        /// Parse filename and extract information.
        /// 
        /// Path to file.
        /// Part of the filename only containing the extra information.
        /// Returns null or an  object if parsing is successful.
        public ExternalPathParserResult? ParseFile(string path, string? extraString)
        {
            if (path.Length == 0)
            {
                return null;
            }
            var extension = Path.GetExtension(path.AsSpan());
            if (!(_type == DlnaProfileType.Subtitle && _namingOptions.SubtitleFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
                && !(_type == DlnaProfileType.Audio && _namingOptions.AudioFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
                && !(_type == DlnaProfileType.Lyric && _namingOptions.LyricFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase)))
            {
                return null;
            }
            var pathInfo = new ExternalPathParserResult(path);
            if (string.IsNullOrEmpty(extraString))
            {
                return pathInfo;
            }
            foreach (var separator in _namingOptions.MediaFlagDelimiters)
            {
                var languageString = extraString;
                var titleString = string.Empty;
                const int SeparatorLength = 1;
                while (languageString.Length > 0)
                {
                    int lastSeparator = languageString.LastIndexOf(separator);
                    if (lastSeparator == -1)
                    {
                          break;
                    }
                    string currentSlice = languageString[lastSeparator..];
                    string currentSliceWithoutSeparator = currentSlice[SeparatorLength..];
                    if (_namingOptions.MediaDefaultFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
                    {
                        pathInfo.IsDefault = true;
                        extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                        languageString = languageString[..lastSeparator];
                        continue;
                    }
                    if (_namingOptions.MediaForcedFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
                    {
                        pathInfo.IsForced = true;
                        extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                        languageString = languageString[..lastSeparator];
                        continue;
                    }
                    // Try to translate to three character code
                    var culture = _localizationManager.FindLanguageInfo(currentSliceWithoutSeparator);
                    if (culture is not null && pathInfo.Language is null)
                    {
                        pathInfo.Language = culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase)
                                          ? culture.Name
                                          : culture.ThreeLetterISOLanguageName;
                        extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                    }
                    else if (culture is not null && pathInfo.Language == "hin")
                    {
                        // Hindi language code "hi" collides with a hearing impaired flag - use as Hindi only if no other language is set
                        pathInfo.IsHearingImpaired = true;
                        pathInfo.Language = culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase)
                                          ? culture.Name
                                          : culture.ThreeLetterISOLanguageName;
                        extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                    }
                    else if (_namingOptions.MediaHearingImpairedFlags.Any(s => currentSliceWithoutSeparator.Equals(s, StringComparison.OrdinalIgnoreCase)))
                    {
                        pathInfo.IsHearingImpaired = true;
                        extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                    }
                    else
                    {
                        titleString = currentSlice + titleString;
                    }
                    languageString = languageString[..lastSeparator];
                }
                pathInfo.Title = titleString.Length >= SeparatorLength ? titleString[SeparatorLength..] : null;
            }
            return pathInfo;
        }
    }
}