using System.Text.Json;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Debugging;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Scripts;
using ZB.MOM.WW.ScadaBridge.ScriptAnalysis;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
///
/// Outcome of a Flow Debugger run or replay as the page consumes it: the built
/// (null on failure), the raw server result (null when the command
/// itself was refused), and a classified error.
///
/// The flow graph built from the returned audit events; null when the command failed outright.
/// The server's ; null when no result came back.
/// Human-readable failure, null on success.
/// Machine-readable failure code (STANDBY_NODE, NO_TRIGGER_WITHIN_WINDOW, UNAUTHORIZED, SERVICE_UNAVAILABLE, …), null on success.
///
/// Step logs (design 2026-09-09 D7): true when the inline trace collector dropped low-priority
/// ScriptLog rows to protect room for the step rows — the run's lines are incomplete inline,
/// while Replay (which reads the never-truncated audit store) is complete. Mirrors
/// so the page can note it without unwrapping the raw result.
///
public sealed record FlowDebugOutcome(
FlowGraph? Graph, FlowDebugRunResult? Raw, string? Error, string? ErrorCode, bool LogsTruncated = false)
{
/// True when a graph was built (the run may still have finished incomplete — see ).
public bool Success => Graph != null && Error == null;
/// Creates a failed outcome.
public static FlowDebugOutcome Fail(string error, string errorCode) => new(null, null, error, errorCode);
}
///
/// Outcome of a Retry / Discard relayed from a Flow Debugger node (follow-ups plan 2026-09-06 D4).
/// is operator-facing and uses the same wording as the Site Calls /
/// Notification report pages, whether the relay was refused before it left the page or the
/// owning site / outbox answered.
///
/// True when the relay was applied (site Applied, or outbox success).
/// What happened, in the report pages' words.
public sealed record FlowOutboundActionResult(bool Success, string Message);
///
/// One script of an instance as the Flow Debugger's script picker shows it (design 2026-09-08 §5):
/// canonical name, trigger kind, the trigger's attribute for write kinds, the effective parameter
/// definitions for call kinds, and the script's own execution timeout (client Ask sizing).
///
/// Path-qualified script name from the flattened configuration (Module.Script for a composed member).
/// The effective trigger type, or null when the script has none.
/// The monitored attribute of a write-kind trigger; null for every other kind.
/// JSON parameter definitions the Inputs card renders for a call kind; null = none.
/// The script's own execution timeout, or null to use the site default.
public sealed record FlowScriptOption(
string CanonicalName, string? TriggerType, string? TriggerAttribute,
string? ParameterDefinitions, int? ExecutionTimeoutSeconds)
{
/// True when the debugger fires this script by writing .
public bool IsWriteKind => ScriptTriggerAttribute.IsWriteKind(TriggerType);
/// Picker label suffix: ValueChange: Level, Call, no trigger…
public string TriggerLabel => string.IsNullOrWhiteSpace(TriggerType) ? "no trigger"
: TriggerAttribute is { } a ? $"{TriggerType}: {a}" : TriggerType!;
}
///
/// CentralUI facade over the Flow Debugger (design 2026-09-05 §5.5/§7.1, script entry
/// 2026-09-08 §5): the instance's script list read from its flattened configuration, static
/// shape prediction from script syntax, and the four management commands (Live run of a
/// method, of a script, of a value change; Replay) dispatched to the per-node ManagementActor
/// through the in-process ManagementActorHolder — the SAME Ask path the HTTP
/// /management endpoint uses, so the server stays the single enforcer of the Deployer
/// gate and the active-node refusal (STANDBY_NODE).
///
public interface IFlowDebugService
{
/// Predicts the flow shape of an inbound API method from its script and the site scripts its constant routes resolve to.
/// The method id.
/// Cancellation token.
/// The predicted flow; when the method does not exist.
Task PredictMethodAsync(int apiMethodId, CancellationToken cancellationToken = default);
/// The instance's scripts from its flattened configuration, ordered by canonical name; empty when the instance does not exist.
/// The instance id.
/// Cancellation token.
Task> GetInstanceScriptsAsync(int instanceId, CancellationToken cancellationToken = default);
/// Predicts the flow of running : the write + spawned script for a write kind, a RouteCall root + the script for a call kind.
/// The instance id.
/// Canonical script name (case-insensitive).
/// Cancellation token.
Task PredictScriptAsync(int instanceId, string scriptName, CancellationToken cancellationToken = default);
/// Runs an inbound API method with tracing on the active central node and returns the flow.
/// The method id.
/// Flat JSON object of parameters, or null.
/// Cancellation token.
Task RunMethodAsync(int apiMethodId, JsonElement? parameters, CancellationToken cancellationToken = default);
/// Runs a script by name (write kinds take , call kinds ) and returns the flow.
/// The instance id.
/// Canonical script name (case-insensitive).
/// Call kinds: flat JSON object of parameters, or null.
/// Write kinds: the new value for the trigger's attribute, in canonical string form.
/// Cancellation token.
Task RunScriptAsync(int instanceId, string scriptName, JsonElement? parameters, string? value, CancellationToken cancellationToken = default);
/// Rebuilds a past flow from the central audit store.
/// Any execution id in the chain.
/// Cancellation token.
Task ReplayAsync(Guid executionId, CancellationToken cancellationToken = default);
///
/// Relays a Retry of a parked outbound node to its owner — the Site Call Audit relay for an
/// / (keyed by the step's
/// = TrackedOperationId and ),
/// the Notification Outbox for a (CorrelationId =
/// NotificationId). A step that is not outbound, not ,
/// has no correlation id, or (site kinds) no site id is refused with a message and never relayed.
///
/// The outbound step to retry.
/// Cancellation token.
Task RetryOutboundAsync(FlowStep step, CancellationToken cancellationToken = default);
///
/// Relays a Discard of a parked outbound node to its owner. Same routing and refusals as
/// .
///
/// The outbound step to discard.
/// Cancellation token.
Task DiscardOutboundAsync(FlowStep step, CancellationToken cancellationToken = default);
}