using System.Collections.Generic;
using System.Runtime.CompilerServices;
using AnalyticsBLL.AnalysisAggregation;
using AnalyticsDAL.DTO.AnalysisAggregation.V1;
using FastEndpoints;
using GB5Shared.DTO.Framework.Login;
using GB5Shared.DTO.Framework.ResponseStandard;
using GB5Shared.DTO.Report;
using GB5Shared.FastEndPoint;
using static GB5Shared.GB5Constant.Constant;
namespace AnalyticsSL.EndPoints.BI
{
/// The unified BI engine endpoint — resolves any of the three MBICATALOG dataset
/// kinds (Warehouse/AnalysisQuery/ApiService) via IAnalysisAggregationService and returns
/// the shaped AnalysisResult contract.
///
/// Deliberately separate from the legacy AnalysisDynamicOutput.cs (AnalysisQueryId +
/// ReportViewId params, flat JSON list response) — that endpoint's shipped contract stays
/// untouched for existing consumers. This endpoint inherits BaseReportEndpoint so
/// Excel/CSV/PDF/NDJSON export come for free via IReportExport, without duplicating any
/// export plumbing.
public class RunBIQuery : BaseReportEndpoint>
{
private readonly IAnalysisAggregationService _aggregationService;
public RunBIQuery(IAnalysisAggregationService aggregationService)
{
_aggregationService = aggregationService;
}
public override void Configure()
{
Post("/BI/RunBIQuery");
AllowAnonymous();
}
public record RunBIQueryParameters(
[property: FromHeader] string Login,
[property: FromBody] AnalysisQueryDefinition Definition
);
// Export path — streams ALL rows (per BaseReportEndpoint contract, paging is ignored here).
protected override async IAsyncEnumerable> ExecuteReportAsync(
RunBIQueryParameters req, LoginDTO login, [EnumeratorCancellation] CancellationToken ct)
{
var result = await _aggregationService.ExecuteAsync(req.Definition, login, ct).ConfigureAwait(false);
foreach (var row in result.Data)
yield return row;
}
// Plain-JSON/UI-grid path — overridden (per BaseReportEndpoint's documented extension
// point) to return the full AnalysisResult (meta + data), not just a capped flat list.
protected override async Task> ExecutePagedAsync(
RunBIQueryParameters req, LoginDTO login, CancellationToken ct)
{
var result = await _aggregationService.ExecuteAsync(req.Definition, login, ct).ConfigureAwait(false);
// NOT_REQUIRED here — BLL-level IDALCache already caches the computed AnalysisResult
// (AnalysisAggregationService §7); caching again at the SL response layer under a
// different key scheme would double-cache the same result for no benefit.
return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse(
result, CacheKeyLevel.NOT_REQUIRED, login);
}
// BaseReportEndpoint.HandleAsync requires a ReportCallingDTO on the request to trigger
// export formats; RunBIQueryParameters intentionally has none (AnalysisQueryDefinition
// is the sole FromBody payload, matching this module's one-FromBody-property convention —
// see SaveAnalysis.cs/AnalysisDynamicOutput.cs). Synthesize a minimal one instead of adding
// an export-specific field to the versioned analytics contract.
protected override ReportCallingDTO? GetReportCallingDTOFromRequest(RunBIQueryParameters req)
=> new ReportCallingDTO { ReportTitle = "Analysis Result" };
}
}