LabelTemplateLabelIdHelper.cs 4.71 KB
using System.Text.Json;
using System.Text.RegularExpressions;
using FoodLabeling.Application.Contracts.Dtos.LabelTemplate;

namespace FoodLabeling.Application.Helpers;

/// <summary>
/// 模板「Entered Automatically → Label ID」控件识别与展示文案填充。
/// </summary>
public static class LabelTemplateLabelIdHelper
{
    private static readonly Regex LabelIdElementNameRe = new(
        "^labelid\\d*$",
        RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

    public static bool IsLabelIdElement(
        string? typeAdd,
        string? elementName,
        string? valueSourceType,
        string? elementType)
    {
        var ta = (typeAdd ?? string.Empty).Trim().ToLowerInvariant();
        if (ta.StartsWith("auto_", StringComparison.Ordinal) && ta.Contains("label id", StringComparison.Ordinal))
        {
            return true;
        }

        var slug = Regex.Replace((elementName ?? string.Empty).Trim().ToLowerInvariant(), "[^a-z0-9]", string.Empty);
        if (LabelIdElementNameRe.IsMatch(slug))
        {
            return true;
        }

        if (string.Equals(valueSourceType, "AUTO_DB", StringComparison.OrdinalIgnoreCase)
            && string.Equals(elementType, "TEXT_STATIC", StringComparison.OrdinalIgnoreCase)
            && slug.StartsWith("labelid", StringComparison.Ordinal))
        {
            return true;
        }

        return false;
    }

    public static bool TemplateContainsLabelId(IEnumerable<LabelTemplateElementDto>? elements) =>
        elements?.Any(e => IsLabelIdElement(e.TypeAdd, e.ElementName, e.ValueSourceType, e.ElementType)) == true;

    public static string FormatDisplayLine(string rawId, IReadOnlyDictionary<string, object?>? config)
    {
        var id = (rawId ?? string.Empty).Trim();
        var prefix = ReadConfigString(config, "prefix", "Prefix", "LABEL ID: ").Trim();
        if (string.IsNullOrWhiteSpace(id))
        {
            return string.IsNullOrWhiteSpace(prefix) ? "—" : $"{prefix}—";
        }

        if (!string.IsNullOrWhiteSpace(prefix)
            && id.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
        {
            return id;
        }

        if (string.IsNullOrWhiteSpace(prefix))
        {
            return id;
        }

        var needsSpace = !prefix.EndsWith(':') && !prefix.EndsWith(' ');
        return needsSpace ? $"{prefix} {id}" : $"{prefix}{id}";
    }

    public static void ApplyLabelIdToElements(
        IList<LabelTemplateElementDto> elements,
        string rawDisplayId)
    {
        if (elements.Count == 0 || string.IsNullOrWhiteSpace(rawDisplayId))
        {
            return;
        }

        foreach (var el in elements)
        {
            if (!IsLabelIdElement(el.TypeAdd, el.ElementName, el.ValueSourceType, el.ElementType))
            {
                continue;
            }

            var cfg = ParseConfigDictionary(el.ConfigJson);
            var line = FormatDisplayLine(rawDisplayId, cfg);
            UpsertConfigValue(cfg, "text", line);
            UpsertConfigValue(cfg, "Text", line);
            el.ConfigJson = cfg;
        }
    }

    private static string ReadConfigString(
        IReadOnlyDictionary<string, object?>? config,
        string key1,
        string key2,
        string fallback)
    {
        if (config is null)
        {
            return fallback;
        }

        if (config.TryGetValue(key1, out var v1) && v1 != null)
        {
            return v1.ToString() ?? fallback;
        }

        if (config.TryGetValue(key2, out var v2) && v2 != null)
        {
            return v2.ToString() ?? fallback;
        }

        return fallback;
    }

    private static Dictionary<string, object?> ParseConfigDictionary(object? configJson)
    {
        if (configJson is null)
        {
            return new Dictionary<string, object?>();
        }

        if (configJson is Dictionary<string, object?> dict)
        {
            return new Dictionary<string, object?>(dict);
        }

        if (configJson is JsonElement je && je.ValueKind == JsonValueKind.Object)
        {
            return JsonSerializer.Deserialize<Dictionary<string, object?>>(je.GetRawText())
                   ?? new Dictionary<string, object?>();
        }

        try
        {
            return JsonSerializer.Deserialize<Dictionary<string, object?>>(JsonSerializer.Serialize(configJson))
                   ?? new Dictionary<string, object?>();
        }
        catch
        {
            return new Dictionary<string, object?>();
        }
    }

    private static void UpsertConfigValue(Dictionary<string, object?> cfg, string key, object? value)
    {
        if (cfg.ContainsKey(key))
        {
            cfg[key] = value;
            return;
        }

        cfg.Add(key, value);
    }
}