namespace Greencore.platform.rules; /// Resultado explícito de una condición; la evidencia pertenece a esta ejecución. public sealed record ConditionResult(bool IsSatisfied, object? Evidence = null); public enum RuleNodeKind { Leaf, AllOf, AnyOf, Not, When, Prerequisite } /// Definición identificable e inmutable, sin referencias a datos de una ejecución. public sealed class RuleDefinition { public string Id { get; } public bool IsAsync { get; } public Func? Condition { get; } public Func> AsyncCondition { get; } public RuleDefinition(string id, Func condition) { ArgumentException.ThrowIfNullOrWhiteSpace(id); ArgumentNullException.ThrowIfNull(condition); Id = id; Condition = condition; AsyncCondition = (value, context, _) => ValueTask.FromResult(condition(value, context)); } public RuleDefinition(string id, Func> condition) { ArgumentException.ThrowIfNullOrWhiteSpace(id); ArgumentNullException.ThrowIfNull(condition); Id = id; IsAsync = true; AsyncCondition = condition; } public RuleNode At(string nodeId, string? path = null) => new(nodeId, RuleNodeKind.Leaf, [], this, path); public RuleDefinition Select(Func selector) { ArgumentNullException.ThrowIfNull(selector); return Condition is { } sync ? new(Id, (parent, context) => sync(selector(parent), context)) : new(Id, (parent, context, token) => AsyncCondition(selector(parent), context, token)); } } public readonly record struct NoRuleContext; public static class RuleDefinition { public static RuleDefinition WithContext(this RuleDefinition definition) { ArgumentNullException.ThrowIfNull(definition); return definition.Condition is { } sync ? new(definition.Id, (value, _) => sync(value, default)) : new(definition.Id, (value, _, token) => definition.AsyncCondition(value, default, token)); } public static RuleDefinition For(string id, IRule condition) { ArgumentNullException.ThrowIfNull(condition); return new(id, (value, _) => new(condition.IsSatisfiedBy(value))); } public static RuleDefinition For(string id, Func condition) { ArgumentNullException.ThrowIfNull(condition); return new(id, (value, context) => new(condition(value, context))); } public static RuleDefinition ForAsync(string id, Func> condition) { ArgumentNullException.ThrowIfNull(condition); return new(id, async (value, context, token) => new(await condition(value, context, token).ConfigureAwait(false))); } }