using ZB.MOM.WW.OtOpcUa.Commons.Browsing;

namespace ZB.MOM.WW.OtOpcUa.AdminUI.Browsing;

/// <summary>
///     Outcome of <see cref="IBrowserSessionService.OpenAsync"/>. On success
///     <paramref name="Ok"/> is <see langword="true"/> and <paramref name="Token"/> is the
///     registry handle; on failure <paramref name="Message"/> carries a human-readable
///     diagnostic for the UI's error chip.
/// </summary>
/// <param name="Ok">True iff the browse session was opened and registered.</param>
/// <param name="Message">Failure diagnostic, or <see langword="null"/> on success.</param>
/// <param name="Token">Registry handle on success; <see cref="Guid.Empty"/> on failure.</param>
public sealed record BrowseOpenResult(bool Ok, string? Message, Guid Token);

/// <summary>
///     Scoped Razor-page facade over the in-process browse-session machinery. Owns
///     driver-type dispatch on open and per-call timeout enforcement on expand/attributes.
/// </summary>
public interface IBrowserSessionService
{
    /// <summary>Opens a session against the named driver type using the given JSON config.
    /// Never throws — all errors are surfaced via <see cref="BrowseOpenResult"/>.</summary>
    Task<BrowseOpenResult> OpenAsync(string driverType, string configJson, CancellationToken ct);

    /// <summary>Returns the root nodes of an open session. Throws
    /// <see cref="BrowseSessionNotFoundException"/> if the token is unknown.</summary>
    Task<IReadOnlyList<BrowseNode>> RootAsync(Guid token, CancellationToken ct);

    /// <summary>Returns the direct children of <paramref name="nodeId"/> in an open session.
    /// Throws <see cref="BrowseSessionNotFoundException"/> if the token is unknown.</summary>
    Task<IReadOnlyList<BrowseNode>> ExpandAsync(Guid token, string nodeId, CancellationToken ct);

    /// <summary>Returns the attributes of <paramref name="nodeId"/> in an open session. Throws
    /// <see cref="BrowseSessionNotFoundException"/> if the token is unknown.</summary>
    Task<IReadOnlyList<AttributeInfo>> AttributesAsync(Guid token, string nodeId, CancellationToken ct);

    /// <summary>Removes the session from the registry and disposes it. No-op for unknown tokens.</summary>
    Task CloseAsync(Guid token);
}

/// <summary>
///     Raised by the service layer when a caller references a token that is not
///     (or no longer) in the registry — typically because the reaper evicted it
///     between calls.
/// </summary>
public sealed class BrowseSessionNotFoundException(Guid token)
    : InvalidOperationException($"Browse session {token} not found (may have been reaped).");
