using System;
using Emby.Naming.Common;

namespace Emby.Naming.Video
{
    /// <summary>
    /// Parse 3D format related flags.
    /// </summary>
    public static class Format3DParser
    {
        // Static default result to save on allocation costs.
        private static readonly Format3DResult _defaultResult = new (false, null);

        /// <summary>
        /// Parse 3D format related flags.
        /// </summary>
        /// <param name="path">Path to file.</param>
        /// <param name="namingOptions">The naming options.</param>
        /// <returns>Returns <see cref="Format3DResult"/> object.</returns>
        public static Format3DResult Parse(ReadOnlySpan<char> path, NamingOptions namingOptions)
        {
            int oldLen = namingOptions.VideoFlagDelimiters.Length;
            Span<char> delimiters = stackalloc char[oldLen + 1];
            namingOptions.VideoFlagDelimiters.AsSpan().CopyTo(delimiters);
            delimiters[oldLen] = ' ';

            return Parse(path, delimiters, namingOptions);
        }

        private static Format3DResult Parse(ReadOnlySpan<char> path, ReadOnlySpan<char> delimiters, NamingOptions namingOptions)
        {
            foreach (var rule in namingOptions.Format3DRules)
            {
                var result = Parse(path, rule, delimiters);

                if (result.Is3D)
                {
                    return result;
                }
            }

            return _defaultResult;
        }

        private static Format3DResult Parse(ReadOnlySpan<char> path, Format3DRule rule, ReadOnlySpan<char> delimiters)
        {
            bool is3D = false;
            string? format3D = null;

            // If there's no preceding token we just consider it found
            var foundPrefix = string.IsNullOrEmpty(rule.PrecedingToken);
            while (path.Length > 0)
            {
                var index = path.IndexOfAny(delimiters);
                if (index == -1)
                {
                    index = path.Length - 1;
                }

                var currentSlice = path[..index];
                path = path[(index + 1)..];

                if (!foundPrefix)
                {
                    foundPrefix = currentSlice.Equals(rule.PrecedingToken, StringComparison.OrdinalIgnoreCase);
                    continue;
                }

                is3D = foundPrefix && currentSlice.Equals(rule.Token, StringComparison.OrdinalIgnoreCase);

                if (is3D)
                {
                    format3D = rule.Token;
                    break;
                }
            }

            return is3D ? new Format3DResult(true, format3D) : _defaultResult;
        }
    }
}