using System.Net;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Html;

namespace JobsMedical.Web.Services;

/// <summary>Wraps query terms in &lt;mark&gt; for result highlighting (HTML-safe).</summary>
public static class SearchHighlight
{
    public static HtmlString Mark(string? text, string? query)
    {
        if (string.IsNullOrEmpty(text)) return HtmlString.Empty;
        var encoded = WebUtility.HtmlEncode(text);
        if (string.IsNullOrWhiteSpace(query)) return new HtmlString(encoded);

        var terms = query.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
            .Where(t => t.Length >= 2)
            .Select(t => Regex.Escape(WebUtility.HtmlEncode(t)))
            .Distinct()
            .ToList();
        if (terms.Count == 0) return new HtmlString(encoded);

        var pattern = string.Join("|", terms);
        var marked = Regex.Replace(encoded, pattern, m => $"<mark>{m.Value}</mark>", RegexOptions.IgnoreCase);
        return new HtmlString(marked);
    }

    /// <summary>
    /// Elasticsearch-style highlight fragment: finds the first matching term in <paramref name="text"/>,
    /// returns a window of ±<paramref name="radius"/> chars around it with the terms marked and ellipses
    /// at the cut points. Empty when nothing matches (so callers can hide the line).
    /// </summary>
    public static HtmlString Snippet(string? text, string? query, int radius = 70)
    {
        if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(query)) return HtmlString.Empty;
        var terms = query.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
            .Where(t => t.Length >= 2).ToList();
        if (terms.Count == 0) return HtmlString.Empty;

        var flat = Regex.Replace(text, @"\s+", " ").Trim();
        int idx = -1, matchLen = 0;
        foreach (var t in terms)
        {
            var i = flat.IndexOf(t, StringComparison.OrdinalIgnoreCase);
            if (i >= 0 && (idx < 0 || i < idx)) { idx = i; matchLen = t.Length; }
        }
        if (idx < 0) return HtmlString.Empty;

        var start = Math.Max(0, idx - radius);
        var end = Math.Min(flat.Length, idx + matchLen + radius);
        var slice = flat.Substring(start, end - start).Trim();
        var prefix = start > 0 ? "…" : "";
        var suffix = end < flat.Length ? "…" : "";
        return new HtmlString(prefix + Mark(slice, query).Value + suffix);
    }
}
