using ZB.MOM.WW.OtOpcUa.Core.Abstractions;

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

/// <summary>
///     What the virtual-tag engine pulls driver-tag values from. Implementations
///     shipped in Stream G bridge this to <see cref="IReadable"/> + <see cref="ISubscribable"/>
///     on the live driver instances; tests use an in-memory fake.
/// </summary>
/// <remarks>
///     <para>
///         The read path is synchronous because user scripts call
///         <c>ctx.GetTag(path)</c> inline — blocking on a driver wire call per-script
///         evaluation would kill throughput. Implementations are expected to serve
///         from a last-known-value cache populated by the subscription callbacks.
///     </para>
///     <para>
///         The subscription path feeds <see cref="VirtualTagEngine"/>'s
///         <c>OnUpstreamChange</c> callback, which updates the engine's value cache and
///         schedules <c>CascadeAsync</c> to re-evaluate every change-driven dependent in
///         topological order. One subscription per distinct upstream tag path; the
///         engine tracks the mapping itself.
///     </para>
/// </remarks>
public interface ITagUpstreamSource
{
    /// <summary>
    ///     Synchronous read returning the last-known value + quality for
    ///     <paramref name="path"/>. Returns a <c>BadNodeIdUnknown</c>-quality snapshot
    ///     when the path isn't configured.
    /// </summary>
    /// <param name="path">The tag path to read.</param>
    /// <returns>The last-known value + quality snapshot for <paramref name="path"/>.</returns>
    DataValueSnapshot ReadTag(string path);

    /// <summary>
    ///     Register an observer that fires every time the upstream value at
    ///     <paramref name="path"/> changes. Returns an <see cref="IDisposable"/> the
    ///     engine disposes when the virtual-tag config is reloaded or the engine shuts
    ///     down, so source-side subscriptions don't leak.
    /// </summary>
    /// <param name="path">The tag path to subscribe to.</param>
    /// <param name="observer">The callback to invoke when the value changes.</param>
    /// <returns>An <see cref="IDisposable"/> that cancels the subscription when disposed.</returns>
    IDisposable SubscribeTag(string path, Action<string, DataValueSnapshot> observer);
}
