using System.Diagnostics.CodeAnalysis;

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

/// <summary>
///     v3: resolves a driver subscription/read/write reference — which is now always a
///     <c>RawPath</c> — to the driver's internal tag-definition. The lookup is a single authored-table
///     hit: each deploy hands the driver its authored raw tags keyed by RawPath (see
///     <see cref="RawTagEntry"/>), the driver builds a <c>RawPath → TDef</c> table from them, and this
///     resolver wraps that table's lookup. The pre-v3 blob-parse fallback (an equipment tag whose
///     reference WAS its raw <c>TagConfig</c> JSON) is retired: a miss is a miss — <see cref="TryResolve"/>
///     returns <see langword="false"/> and the driver surfaces Bad quality, never a parse attempt.
/// </summary>
/// <typeparam name="TDef">The driver's internal tag-definition type.</typeparam>
public sealed class EquipmentTagRefResolver<TDef> where TDef : class
{
    private readonly Func<string, TDef?> _byRawPath;

    /// <summary>Initializes a new instance of the <see cref="EquipmentTagRefResolver{TDef}"/> class.</summary>
    /// <param name="byRawPath">The driver's authored-table lookup (RawPath → definition; null on miss).</param>
    public EquipmentTagRefResolver(Func<string, TDef?> byRawPath)
    {
        ArgumentNullException.ThrowIfNull(byRawPath);
        _byRawPath = byRawPath;
    }

    /// <summary>True when <paramref name="rawPath"/> resolves to an authored tag-definition.</summary>
    /// <param name="rawPath">The RawPath wire reference handed to the driver.</param>
    /// <param name="def">
    ///     The resolved tag-definition when this returns <see langword="true"/>. When this returns
    ///     <see langword="false"/> the value is undefined — callers must not use it.
    /// </param>
    /// <returns><see langword="true"/> when a definition was found.</returns>
    public bool TryResolve(string rawPath, [MaybeNullWhen(false)] out TDef def)
    {
        def = _byRawPath(rawPath);
        return def is not null;
    }

    /// <summary>
    ///     No-op retained for call-site compatibility. v3 holds no transient parse cache — the driver
    ///     rebuilds its authored <c>RawPath → TDef</c> table on reinitialise, and this resolver reads
    ///     the driver's live table by closure, so there is nothing to clear here.
    /// </summary>
    public void Clear()
    {
    }
}

/// <summary>
///     The unit of tag delivery from the deploy artifact to a driver: one authored raw
///     <c>Tag</c>, identified by its <see cref="RawPath"/> (the v3 identity), carrying the
///     driver-specific address blob (<see cref="TagConfig"/>) the driver dials and the platform flags
///     the driver needs. A driver maps each entry to its typed definition (keyed by RawPath) via its
///     own <c>TagConfig → definition</c> factory at table-build time.
/// </summary>
/// <param name="RawPath">The tag's cluster-scoped RawPath — the driver wire reference / identity.</param>
/// <param name="TagConfig">The tag's schemaless driver-specific <c>TagConfig</c> JSON (the dialled address).</param>
/// <param name="WriteIdempotent">Whether writes to this tag are safe to replay (R2 resilience contract).</param>
/// <param name="DeviceName">
///     The name of the <c>Device</c> this tag lives under (the RawPath's device segment). Multi-device
///     drivers route the tag to its device/connection by this name; single-device drivers ignore it.
///     Populated by the deploy artifact (which built the RawPath and therefore knows the device);
///     defaults to empty for callers that don't need device routing.
/// </param>
public sealed record RawTagEntry(string RawPath, string TagConfig, bool WriteIdempotent, string DeviceName = "");
