namespace ZB.MOM.WW.OtOpcUa.Commons.Engines;

/// <summary>
///     Abstraction over the scripted-alarm predicate engine. Production binds this to a
///     wrapper around <c>ScriptedAlarmEngine</c> from <c>Core.ScriptedAlarms</c>; default
///     binding is <see cref="NullScriptedAlarmEvaluator"/> which keeps the alarm in its
///     current state (so an unconfigured node never spuriously alarms).
/// </summary>
public interface IScriptedAlarmEvaluator
{
    /// <summary>Evaluates an alarm predicate against the provided dependencies.</summary>
    /// <param name="alarmId">The unique identifier of the alarm being evaluated.</param>
    /// <param name="predicate">The predicate expression to evaluate.</param>
    /// <param name="dependencies">Read-only dictionary of variable names to values for predicate evaluation.</param>
    /// <returns>Result containing success flag, alarm active state, and optional failure reason.</returns>
    ScriptedAlarmEvalResult Evaluate(string alarmId, string predicate, IReadOnlyDictionary<string, object?> dependencies);
}

/// <summary>Result of one alarm-predicate evaluation. <c>Active</c> is only meaningful when
/// <c>Success</c> is true; on failure the caller should keep the prior state and log Reason.</summary>
public sealed record ScriptedAlarmEvalResult(bool Success, bool Active, string? Reason)
{
    /// <summary>Creates a successful alarm evaluation result with the given active state.</summary>
    /// <param name="active">Whether the alarm condition is active.</param>
    /// <returns>A successful evaluation result.</returns>
    public static ScriptedAlarmEvalResult Ok(bool active) => new(true, active, null);

    /// <summary>Creates a failed alarm evaluation result with the given reason.</summary>
    /// <param name="reason">Description of the evaluation failure cause.</param>
    /// <returns>A failed evaluation result.</returns>
    public static ScriptedAlarmEvalResult Failure(string reason) => new(false, false, reason);
}

/// <summary>Default that always returns <c>Active = false, Success = true</c>. Safe no-op:
/// no alarm fires when no real engine is bound.</summary>
public sealed class NullScriptedAlarmEvaluator : IScriptedAlarmEvaluator
{
    public static readonly NullScriptedAlarmEvaluator Instance = new();
    private NullScriptedAlarmEvaluator() { }
    /// <summary>Returns an inactive alarm result for every evaluation (safe no-op behavior).</summary>
    /// <param name="alarmId">The alarm identifier (ignored).</param>
    /// <param name="predicate">The predicate expression (ignored).</param>
    /// <param name="dependencies">The variable dependencies (ignored).</param>
    /// <returns>Always returns an inactive alarm result.</returns>
    public ScriptedAlarmEvalResult Evaluate(string alarmId, string predicate, IReadOnlyDictionary<string, object?> dependencies)
        => ScriptedAlarmEvalResult.Ok(active: false);
}
