using Grpc.Core;
using ZB.MOM.WW.GalaxyRepository;
using ZB.MOM.WW.GalaxyRepository.Grpc;

namespace ZB.MOM.WW.MxGateway.Server.Dashboard;

/// <summary>
///     Default <see cref="IDashboardBrowseService"/>. Delegates to
///     <see cref="GalaxyBrowseProjector"/> via the shared
///     <see cref="IGalaxyHierarchyCache"/>; no SQL hop, no gRPC self-call. Translates
///     the projector's <see cref="RpcException"/> on unknown parent into a friendly
///     <see cref="BrowseLevelResult.Error"/> so the Blazor circuit does not see an
///     unhandled exception.
/// </summary>
public sealed class DashboardBrowseService(IGalaxyHierarchyCache cache) : IDashboardBrowseService
{
    /// <inheritdoc />
    public ulong CurrentCacheSequence => (ulong)cache.Current.Sequence;

    /// <inheritdoc />
    public BrowseLevelResult GetRoots(BrowseFilterArgs filter)
        => ProjectLevel(parentId: null, filter);

    /// <inheritdoc />
    public BrowseLevelResult GetChildren(int parentGobjectId, BrowseFilterArgs filter)
        => ProjectLevel(parentId: parentGobjectId, filter);

    private BrowseLevelResult ProjectLevel(int? parentId, BrowseFilterArgs filter)
    {
        ArgumentNullException.ThrowIfNull(filter);

        GalaxyHierarchyCacheEntry entry = cache.Current;
        if (!entry.HasData)
        {
            return new BrowseLevelResult(
                Array.Empty<DashboardBrowseNode>(),
                0,
                (ulong)entry.Sequence,
                Error: "Galaxy hierarchy is not loaded yet.");
        }

        BrowseChildrenRequest request = new()
        {
            TagNameGlob = filter.TagNameGlob ?? string.Empty,
            AlarmBearingOnly = filter.AlarmBearingOnly,
            HistorizedOnly = filter.HistorizedOnly,
        };
        if (parentId is int pid)
        {
            request.ParentGobjectId = pid;
        }

        try
        {
            GalaxyBrowseChildrenResult result = GalaxyBrowseProjector.ProjectChildren(
                entry,
                request,
                browseSubtreeGlobs: null,
                offset: 0,
                pageSize: int.MaxValue);

            List<DashboardBrowseNode> nodes = new(result.Children.Count);
            for (int i = 0; i < result.Children.Count; i++)
            {
                nodes.Add(new DashboardBrowseNode
                {
                    Object = result.Children[i],
                    HasChildrenHint = result.ChildHasChildren[i],
                });
            }
            return new BrowseLevelResult(nodes, result.TotalChildCount, (ulong)entry.Sequence);
        }
        catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound)
        {
            return new BrowseLevelResult(
                Array.Empty<DashboardBrowseNode>(),
                0,
                (ulong)entry.Sequence,
                Error: ex.Status.Detail);
        }
    }
}
