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

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

/// <summary>Test double for <see cref="IBrowseSession"/> used by the registry, reaper,
/// and service tests. All three operations delegate to caller-supplied handlers so each
/// test can shape behaviour; <see cref="DisposeAsync"/> records that it ran and can be
/// instructed to throw via <see cref="ThrowOnDispose"/>.</summary>
internal sealed class FakeBrowseSession : IBrowseSession
{
    /// <inheritdoc />
    public Guid Token { get; } = Guid.NewGuid();

    /// <summary>Mutable so tests can rewind the timestamp into the reaper's eviction window.</summary>
    public DateTime LastUsedUtc { get; set; } = DateTime.UtcNow;

    /// <summary>True once <see cref="DisposeAsync"/> has run to completion.</summary>
    public bool Disposed { get; private set; }

    /// <summary>When true, <see cref="DisposeAsync"/> throws to exercise the reaper's
    /// best-effort dispose path.</summary>
    public bool ThrowOnDispose { get; set; }

    // Suppress CS0649: handlers are test seams — some tests leave them null intentionally.
#pragma warning disable CS0649
    public Func<CancellationToken, Task<IReadOnlyList<BrowseNode>>>? RootHandler;
    public Func<string, CancellationToken, Task<IReadOnlyList<BrowseNode>>>? ExpandHandler;
    public Func<string, CancellationToken, Task<IReadOnlyList<AttributeInfo>>>? AttributesHandler;
#pragma warning restore CS0649

    /// <inheritdoc />
    public Task<IReadOnlyList<BrowseNode>> RootAsync(CancellationToken ct)
        => RootHandler?.Invoke(ct) ?? Task.FromResult<IReadOnlyList<BrowseNode>>(Array.Empty<BrowseNode>());

    /// <inheritdoc />
    public Task<IReadOnlyList<BrowseNode>> ExpandAsync(string nodeId, CancellationToken ct)
        => ExpandHandler?.Invoke(nodeId, ct) ?? Task.FromResult<IReadOnlyList<BrowseNode>>(Array.Empty<BrowseNode>());

    /// <inheritdoc />
    public Task<IReadOnlyList<AttributeInfo>> AttributesAsync(string nodeId, CancellationToken ct)
        => AttributesHandler?.Invoke(nodeId, ct) ?? Task.FromResult<IReadOnlyList<AttributeInfo>>(Array.Empty<AttributeInfo>());

    /// <inheritdoc />
    public ValueTask DisposeAsync()
    {
        if (ThrowOnDispose) throw new InvalidOperationException("dispose-failed");
        Disposed = true;
        return ValueTask.CompletedTask;
    }
}
