using Microsoft.EntityFrameworkCore;
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
namespace ZB.MOM.WW.OtOpcUa.Configuration.Queries;
///
/// Shared query for the cluster-scoped audit view. Audit rows reach ConfigAuditLog by two
/// paths that stamp different columns:
///
/// - the bespoke stored-procedure path stamps ClusterId directly;
/// - the structured AuditWriterActor path stamps NodeId (leaving
/// ClusterId null).
///
/// A cluster-scoped view must surface both, so this query matches rows whose ClusterId
/// equals the cluster or whose NodeId belongs to a node in the cluster
/// (membership from : NodeId → ClusterId).
///
public static class ClusterAuditQuery
{
///
/// Returns the newest audit rows visible for
/// , newest first. Executes one query to resolve the cluster's
/// node IDs, then one filtered query against ConfigAuditLog.
///
/// The config database context.
/// The cluster whose audit rows to fetch.
/// Maximum number of rows to return.
/// Cancellation token.
/// The matching audit rows, newest first.
public static async Task> ForClusterAsync(
OtOpcUaConfigDbContext db, string clusterId, int pageSize, CancellationToken ct = default)
{
var nodeIds = await db.ClusterNodes.AsNoTracking()
.Where(n => n.ClusterId == clusterId)
.Select(n => n.NodeId)
.ToListAsync(ct);
return await db.ConfigAuditLogs.AsNoTracking()
.Where(a => a.ClusterId == clusterId
|| (a.ClusterId == null && a.NodeId != null && nodeIds.Contains(a.NodeId)))
.OrderByDescending(a => a.Timestamp)
.Take(pageSize)
.ToListAsync(ct);
}
}