using System.Globalization;
using Deal.Modules.Kanban.Application.Models;
namespace Deal.Modules.Kanban.Application.ColumnRules;
///
/// Человекочитаемое описание правил колонки для note/подсказки.
///
public static class RulesDescriber
{
///
/// Описывает правила колонки.
///
/// Правила колонки (null/пустые → «без правил (решает ИИ/ML)»).
/// Строка-расшифровка для UI/промпта.
public static string Describe(ContainerRulesDto? rules)
{
if (rules is null)
{
return NoRulesText;
}
var parts = new List();
if (rules.Direction.Count > 0)
{
parts.Add($"направление: {JoinLimited(rules.Direction, DirectionLimit)}");
}
if (rules.Stack.Count > 0)
{
parts.Add($"стек: {JoinLimited(rules.Stack, TermsLimit)}");
}
if (rules.Keywords.Count > 0)
{
parts.Add($"слова: {JoinLimited(rules.Keywords, TermsLimit)}");
}
if (rules.Grade.Count > 0)
{
parts.Add($"грейд: {JoinLimited(rules.Grade, TermsLimit)}");
}
if (rules.Levels is { Count: > 0 })
{
parts.Add($"уровень: {JoinLimited(rules.Levels, TermsLimit)}");
}
if (rules.Locations is { Count: > 0 })
{
parts.Add($"локация: {JoinLimited(rules.Locations, TermsLimit)}");
}
if (rules.Types is { Count: > 0 })
{
parts.Add($"тип: {JoinLimited(rules.Types, TermsLimit)}");
}
if (rules.Exclude.Count > 0)
{
parts.Add($"исключено: {JoinLimited(rules.Exclude, TermsLimit)}");
}
AddRangePart(parts, rules.Budget, "бюджет");
AddRangePart(parts, rules.Prices, "цена");
if (parts.Count == 0)
{
return NoRulesText;
}
string mode = string.Equals(rules.Mode, ColumnRuleModes.Any, StringComparison.OrdinalIgnoreCase)
? AnyModePrefix
: AllModePrefix;
return mode + " · " + string.Join("; ", parts);
}
private const string NoRulesText = "без правил (решает ИИ/ML)";
private const string AllModePrefix = "все условия";
// Префикс режима «любое из условий».
private const string AnyModePrefix = "любое из условий";
private const int DirectionLimit = 6;
private const int TermsLimit = 8;
// Добавляет в описание диапазон группы (бюджет/цена), если задана хотя бы одна граница.
// parts: Накопитель частей описания.
// range: Диапазон группы (null — группа выключена).
// title: Подпись группы («бюджет»/«цена»).
private static void AddRangePart(
List parts,
BudgetRangeDto? range,
string title)
{
if (range is null || (range.From is null && range.To is null))
{
return;
}
string lo = range.From is not null ? range.From.Value.ToString(CultureInfo.InvariantCulture) : string.Empty;
string hi = range.To is not null ? range.To.Value.ToString(CultureInfo.InvariantCulture) : string.Empty;
string cur = range.Cur ?? string.Empty;
parts.Add($"{title}: {lo}–{hi} {cur}".Replace("– ", "–").Replace(" –", "–"));
}
private static string JoinLimited(IReadOnlyList terms, int limit)
{
int count = Math.Min(terms.Count, limit);
return string.Join(", ", terms.Take(count));
}
}