namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Protocol;

/// <summary>
/// Optional capability for an <see cref="IDataConnection"/>
/// implementation that supports a bounded recursive search of the server's
/// address space. A complement to <see cref="IBrowsableDataConnection"/>:
/// where browse walks one level at a time on user demand, search walks the
/// tree itself (bounded by depth + result caps) and returns the nodes whose
/// DisplayName or root-relative path contains a query substring.
///
/// Consumed only by management/UI flows (e.g. the OPC UA tag picker's
/// "find a tag" box on the instance config page) — never by Instance Actors
/// on the hot path.
/// </summary>
public interface IAddressSpaceSearchable
{
    /// <summary>
    /// Walks the server's address space breadth-first from the root, bounded by
    /// <paramref name="maxDepth"/> and <paramref name="maxResults"/>, returning
    /// the nodes whose DisplayName or root-relative path contains
    /// <paramref name="query"/> (case-insensitive substring match).
    /// </summary>
    /// <param name="query">Case-insensitive substring to match against each node's DisplayName and its root-relative path. An empty/whitespace query matches nothing (the walk is skipped).</param>
    /// <param name="maxDepth">Maximum number of levels below the root to descend (Object nodes deeper than this are not expanded). Must be non-negative.</param>
    /// <param name="maxResults">Maximum number of matches to return; when reached the walk stops early and <see cref="AddressSpaceSearchResult.CapReached"/> is set true.</param>
    /// <param name="cancellationToken">Cancellation token; on cancellation the implementation should throw <see cref="OperationCanceledException"/>.</param>
    /// <returns>A task that resolves to the matches found and a flag indicating whether a bound (result cap or node-visit ceiling) cut the walk short.</returns>
    Task<AddressSpaceSearchResult> SearchAddressSpaceAsync(
        string query,
        int maxDepth,
        int maxResults,
        CancellationToken cancellationToken = default);
}

/// <param name="Node">The matched address-space node, carrying its NodeId, DisplayName, NodeClass and (B1) type info.</param>
/// <param name="Path">The matched node's root-relative path: the slash-joined DisplayName chain from the root down to the node (e.g. <c>"/Folder1/Tag1"</c>).</param>
public record AddressSpaceMatch(BrowseNode Node, string Path);

/// <param name="Matches">The matched nodes, in breadth-first discovery order.</param>
/// <param name="CapReached">True when a bound cut the walk short — either <c>maxResults</c> matches were collected or the implementation's node-visit ceiling was hit — so more matches may exist than were returned.</param>
public record AddressSpaceSearchResult(
    IReadOnlyList<AddressSpaceMatch> Matches,
    bool CapReached);
