using System.Collections.Concurrent;

namespace ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms;

/// <summary>
///     Persistence for <see cref="AlarmConditionState"/> across server restarts.
///     Operator-supplied state (EnabledState / AckedState /
///     ConfirmedState / ShelvingState + audit trail) persists; ActiveState is
///     recomputed from the live predicate on startup so operators never re-ack.
/// </summary>
/// <remarks>
///     Stream E wires this to a SQL-backed store against the <c>ScriptedAlarmState</c>
///     table with audit logging through <see cref="Core.Abstractions"/> IAuditLogger.
///     Tests + local dev use <see cref="InMemoryAlarmStateStore"/>.
/// </remarks>
public interface IAlarmStateStore
{
    /// <summary>Loads the alarm state for a specific alarm identifier.</summary>
    /// <param name="alarmId">The alarm identifier.</param>
    /// <param name="ct">Cancellation token.</param>
    /// <returns>The alarm state if found; otherwise null.</returns>
    Task<AlarmConditionState?> LoadAsync(string alarmId, CancellationToken ct);

    /// <summary>Loads all alarm states from the store.</summary>
    /// <param name="ct">Cancellation token.</param>
    /// <returns>A collection of all alarm states.</returns>
    Task<IReadOnlyList<AlarmConditionState>> LoadAllAsync(CancellationToken ct);

    /// <summary>Saves an alarm state to the store.</summary>
    /// <param name="state">The alarm state to save.</param>
    /// <param name="ct">Cancellation token.</param>
    /// <returns>A task representing the save operation.</returns>
    Task SaveAsync(AlarmConditionState state, CancellationToken ct);

    /// <summary>Removes an alarm state from the store.</summary>
    /// <param name="alarmId">The alarm identifier to remove.</param>
    /// <param name="ct">Cancellation token.</param>
    /// <returns>A task representing the remove operation.</returns>
    Task RemoveAsync(string alarmId, CancellationToken ct);
}

/// <summary>In-memory default — used by tests + by dev deployments without a SQL backend.</summary>
public sealed class InMemoryAlarmStateStore : IAlarmStateStore
{
    private readonly ConcurrentDictionary<string, AlarmConditionState> _map
        = new(StringComparer.Ordinal);

    /// <inheritdoc />
    public Task<AlarmConditionState?> LoadAsync(string alarmId, CancellationToken ct)
        => Task.FromResult(_map.TryGetValue(alarmId, out var v) ? v : null);

    /// <inheritdoc />
    public Task<IReadOnlyList<AlarmConditionState>> LoadAllAsync(CancellationToken ct)
        => Task.FromResult<IReadOnlyList<AlarmConditionState>>(_map.Values.ToArray());

    /// <inheritdoc />
    public Task SaveAsync(AlarmConditionState state, CancellationToken ct)
    {
        _map[state.AlarmId] = state;
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task RemoveAsync(string alarmId, CancellationToken ct)
    {
        _map.TryRemove(alarmId, out _);
        return Task.CompletedTask;
    }
}
