using System.Text.Json;
using System.Text.Json.Serialization;
using w4c_workflows.Models;
namespace w4c_workflows.Services.Triggers;
///
/// Typed trigger model parsed from Workflow.TriggerJson. The compiler
/// stores the trigger exactly as it appeared in YAML (camelCase, nulls omitted);
/// this record normalizes it for the trigger engine: the interval string becomes
/// a parsed and the type is guaranteed non-null.
///
public sealed record TriggerSpec(
string Type,
string? Cron,
TimeSpan? Interval,
string? WebhookPath,
string? Stream)
{
private static readonly JsonSerializerOptions Json = new(JsonSerializerDefaults.Web)
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};
///
/// Parses stored trigger JSON. Returns null (with a non-null
/// ) when the JSON is absent, malformed, or the
/// trigger lacks a valid type/interval.
///
public static TriggerSpec? Parse(string? json, out string? error)
{
error = null;
if (string.IsNullOrWhiteSpace(json))
return null;
TriggerDefinition def;
try
{
def = JsonSerializer.Deserialize(json, Json) ?? new TriggerDefinition();
}
catch (JsonException ex)
{
error = ex.Message;
return null;
}
if (string.IsNullOrWhiteSpace(def.Type))
{
error = "trigger.type is missing";
return null;
}
TimeSpan? interval = null;
if (!string.IsNullOrWhiteSpace(def.Interval))
{
if (!DurationParser.TryParse(def.Interval, out var parsed))
{
error = $"trigger.interval '{def.Interval}' is not a valid duration";
return null;
}
interval = parsed;
}
return new TriggerSpec(def.Type, def.Cron, interval, def.WebhookPath, def.Stream);
}
}