using System;
using System.Text.RegularExpressions;
using UnityEngine.UIElements;

namespace UnityEditor.Searcher
{
    static class SearcherHighlighter
    {
        const char k_StartHighlightSeparator = '{';
        const char k_EndHighlightSeparator = '}';
        const string k_HighlightedStyleClassName = "Highlighted";

        public static void HighlightTextBasedOnQuery(VisualElement container, string text, string query)
        {
            var formattedText = text;
            var queryParts = query.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries);
            var regex = string.Empty;
            for (var index = 0; index < queryParts.Length; index++)
            {
                var queryPart = queryParts[index];
                regex += $"({Regex.Escape(queryPart)})";
                if (index < queryParts.Length - 1)
                    regex += "|";
            }

            var matches = Regex.Matches(formattedText, regex, RegexOptions.IgnoreCase);
            foreach (Match match in matches)
            {
                formattedText = formattedText.Replace(match.Value,
                    $"{k_StartHighlightSeparator}{match.Value}{k_EndHighlightSeparator}");
            }

            BuildHighlightLabels(container, formattedText);
        }

        static void BuildHighlightLabels(VisualElement container, string formattedHighlightText)
        {
            if (string.IsNullOrEmpty(formattedHighlightText))
                return;

            var substring = string.Empty;
            var highlighting = false;
            var skipCount = 0;
            foreach (var character in formattedHighlightText.ToCharArray())
            {
                switch (character)
                {
                    // Skip embedded separators
                    // Ex:
                    // Query: middle e
                    // Text: Middle Eastern
                    // Formatted Text: {Middl{e}} {E}ast{e}rn
                    //                      ^ ^
                    case k_StartHighlightSeparator when highlighting:
                        skipCount++;
                        continue;
                    case k_StartHighlightSeparator: {
                        highlighting = true;
                        if (!string.IsNullOrEmpty(substring))
                        {
                            container.Add(new Label(substring));
                            substring = string.Empty;
                        }

                        continue;
                    }
                    case k_EndHighlightSeparator when skipCount > 0:
                        skipCount--;
                        continue;
                    case k_EndHighlightSeparator: {
                        var label = new Label(substring);
                        label.AddToClassList(k_HighlightedStyleClassName);
                        container.Add(label);

                        highlighting = false;
                        substring = string.Empty;

                        continue;
                    }
                    default:
                        substring += character;
                        break;
                }
            }

            if (!string.IsNullOrEmpty(substring))
            {
                var label = new Label(substring);
                if (highlighting)
                    label.AddToClassList(k_HighlightedStyleClassName);
                container.Add(label);
            }
        }
    }
}
