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

/// <summary>
///     Persistence seam for <c>ScriptedAlarmActor</c>'s in-memory state across actor restarts.
///     Captures only the slice the actor's 3-state machine needs (Inactive / Active /
///     Acknowledged + last transition + last-ack user). The fuller GxP audit trail
///     (<see cref="Configuration.Entities.ScriptedAlarmState"/>'s Comments/Confirmed/Shelving)
///     stays in the production engine binding — this seam is the small surface the actor
///     consumes directly.
/// </summary>
public interface IAlarmActorStateStore
{
    /// <summary>Loads the persisted state snapshot for an alarm actor.</summary>
    /// <param name="alarmId">The alarm identifier.</param>
    /// <param name="ct">Cancellation token.</param>
    /// <returns>The alarm state snapshot if found; null if the alarm has no persisted state.</returns>
    Task<AlarmActorStateSnapshot?> LoadAsync(string alarmId, CancellationToken ct);
    /// <summary>Saves the alarm actor state snapshot.</summary>
    /// <param name="snapshot">The state snapshot to persist.</param>
    /// <param name="ct">Cancellation token.</param>
    Task SaveAsync(AlarmActorStateSnapshot snapshot, CancellationToken ct);
}

/// <summary>Persisted slice of <c>ScriptedAlarmActor</c>'s state. Active is NOT persisted —
/// it re-derives from the evaluator on startup per Phase 7 decision #14. <c>State</c> here
/// distinguishes Acknowledged vs not-yet-acknowledged for cases where the actor came up
/// Active and operator interaction had already happened.</summary>
/// <param name="AlarmId">Matches <c>ScriptedAlarm.ScriptedAlarmId</c>.</param>
/// <param name="State">Inactive / Active / Acknowledged — the actor's 3-state enum, projected to string.</param>
/// <param name="LastTransitionUtc">When the actor last transitioned.</param>
/// <param name="LastAckUser">Who acknowledged most recently. Null when never acked.</param>
public sealed record AlarmActorStateSnapshot(
    string AlarmId,
    string State,
    DateTime LastTransitionUtc,
    string? LastAckUser);

/// <summary>No-op default. Bound when no production store is configured (tests, smoke runs).
/// Load returns null → actor boots Inactive; Save is a no-op so state doesn't leak.</summary>
public sealed class NullAlarmActorStateStore : IAlarmActorStateStore
{
    public static readonly NullAlarmActorStateStore Instance = new();
    private NullAlarmActorStateStore() { }
    /// <summary>Always returns null, indicating no persisted state.</summary>
    /// <param name="alarmId">The alarm identifier (unused).</param>
    /// <param name="ct">Cancellation token (unused).</param>
    public Task<AlarmActorStateSnapshot?> LoadAsync(string alarmId, CancellationToken ct) =>
        Task.FromResult<AlarmActorStateSnapshot?>(null);
    /// <summary>Completes immediately without persisting anything.</summary>
    /// <param name="snapshot">The state snapshot (ignored).</param>
    /// <param name="ct">Cancellation token (unused).</param>
    public Task SaveAsync(AlarmActorStateSnapshot snapshot, CancellationToken ct) =>
        Task.CompletedTask;
}
