using System.Text.RegularExpressions;

namespace foodmarket.Application.Common.Email;

/// <summary>Лёгкий «mustache-light» рендерер для email-шаблонов: подстановка
/// `{{key}}` из словаря и условные блоки `{{#key}}...{{/key}}` (показываются
/// только если key есть и значение truthy).
///
/// Не Razor/Liquid — намеренно минимальный набор, потому что эти шаблоны:
/// • короткие и редкие (3 типа писем),
/// • не требуют циклов/выражений (структурированные DTO в коде формирует
///   payload построчно перед рендером),
/// • не должны давать SSRF/RCE-поверхность (как у любого «полноценного»
///   шаблонизатора).
///
/// HTML-escape по умолчанию ВКЛЮЧЁН — `{{name}}` экранирует, `{{{name}}}`
/// (тройные фигурные) вставляет как есть (для уже-готового HTML вставок,
/// типа таблиц). Используйте с осторожностью.</summary>
public static class EmailTemplateRenderer
{
    private static readonly Regex BlockRegex = new(@"\{\{#(\w+)\}\}(.*?)\{\{/\1\}\}", RegexOptions.Singleline | RegexOptions.Compiled);
    private static readonly Regex RawRegex = new(@"\{\{\{(\w+)\}\}\}", RegexOptions.Compiled);
    private static readonly Regex EscRegex = new(@"\{\{(\w+)\}\}", RegexOptions.Compiled);

    public static string Render(string template, IReadOnlyDictionary<string, string?> values)
    {
        // 1. Условные блоки. Truthy = не-null, не пустая строка, не "0", не "false".
        var result = BlockRegex.Replace(template, m =>
        {
            var key = m.Groups[1].Value;
            values.TryGetValue(key, out var v);
            return IsTruthy(v) ? m.Groups[2].Value : "";
        });

        // 2. Raw (без escape). После блоков чтобы тройные внутри условного блока тоже рендерились.
        result = RawRegex.Replace(result, m =>
        {
            values.TryGetValue(m.Groups[1].Value, out var v);
            return v ?? "";
        });

        // 3. Escaped (по умолчанию).
        result = EscRegex.Replace(result, m =>
        {
            values.TryGetValue(m.Groups[1].Value, out var v);
            return v is null ? "" : HtmlEscape(v);
        });

        return result;
    }

    private static bool IsTruthy(string? v) =>
        !string.IsNullOrWhiteSpace(v) && v != "0" && !string.Equals(v, "false", StringComparison.OrdinalIgnoreCase);

    private static string HtmlEscape(string s) => s
        .Replace("&", "&amp;")
        .Replace("<", "&lt;")
        .Replace(">", "&gt;")
        .Replace("\"", "&quot;")
        .Replace("'", "&#39;");
}
