// =============================================================================
// GB5 Framework — IQueryOrchestrator
// Namespace : FrameworkBLL.ReportOrchestration
// Purpose : Central entry point for ALL report and analysis execution.
// Orchestrates: datasource resolution, async decision, URI call
// (standard reports) or dynamic SQL execution (analysis reports),
// pivot transformation, export, caching, and SysJob submission.
//
// What callers do:
// 1. Build a ReportExecutionContext (identity + parameters + call type).
// 2. Call IQueryOrchestrator.ExecuteReportAsync(context).
// 3. Inspect ReportExecutionResult.ResultType:
// SyncCompleted → stream GridData or ExportStream to browser.
// AsyncSubmitted → return SysJobId; Angular shows My Reports inbox.
// Failed → return error response with CorrelationId.
//
// What callers do NOT do:
// - Resolve DB connections.
// - Decide sync vs async.
// - Call module endpoints directly.
// - Generate export files.
// - Submit SysJobs.
//
// Lifetime: Scoped (one instance per HTTP request).
// =============================================================================
using GB5Shared.DTO.Framework.Login;
using GB5Shared.DTO.ReportOrchestration;
using GB5Shared.Enums.ReportOrchestration;
namespace FrameworkBLL.ReportOrchestration
{
///
/// Central orchestrator for report and analysis execution.
/// All module API endpoints and background job workers call this interface;
/// no module should construct DB connections or resolve datasources directly
/// for reporting purposes.
///
public interface IQueryOrchestrator
{
// =====================================================================
// PRIMARY ENTRY POINT
// =====================================================================
///
/// Executes a report or analysis as described by
/// and returns a unified result.
///
///
/// Pipeline stages (in order):
///
/// - Load MREPORTCONFIG / MANALYSISWORKSPACE metadata.
/// - Validate requested ExportFormat against ALLOWEDEXPORTFORMATS.
/// - Evaluate datasource rules (Auto → concrete DataSourceType).
/// - Resolve IDbConnection via IReportConnectionResolver.
/// - Evaluate async decision (AsyncMode + DateRangeDays + policy).
/// -
/// If sync: execute (URI call or dynamic SQL), optionally pivot,
/// export, optionally cache, return SyncCompleted result.
///
/// -
/// If async: submit SysJob with resolved context serialised as
/// TSYSJOB.PARAMETERS, return AsyncSubmitted result with SysJobId.
///
///
///
/// Performance notes:
///
/// - MREPORTCONFIG is cached within the request (Scoped resolver).
/// - Result data is cached in IDistributedCache when
/// MREPORTCONFIG.CACHEDURATIONMINUTES > 0.
/// - NOLOCK hints are applied automatically when
/// MREPORTCONFIG.ISNOLOCKALLOWED = true and provider = SQL Server.
/// - CancellationToken from context is propagated to all async ops.
///
///
///
/// Fully populated execution context. At minimum must carry LoginDTO,
/// ReportId or AnalysisId, CallType, Parameters, RequestedFormat,
/// and CancellationToken.
///
///
/// A with ResultType indicating
/// how the caller should respond to the browser.
/// Never throws — exceptions are caught and returned as
/// with a safe error message.
///
Task ExecuteReportAsync(ReportExecutionContext context);
// =====================================================================
// ASYNC (SYSJOB WORKER) ENTRY POINT
// =====================================================================
///
/// Called by the SysJob worker to execute a previously queued async
/// report. Deserialises the context from TSYSJOB.PARAMETERS, executes,
/// generates the export file, saves it, and updates TSYSJOB.RESULTLOCATION.
///
///
/// This overload always executes synchronously relative to the caller
/// (the worker thread). It does not re-submit as another SysJob.
/// TSYSJOB.RUNSTATUS is managed by the SysJob framework — the worker
/// sets it to Running before calling this, and to Completed/Failed after.
///
///
/// The TSYSJOB.SYSJOBID being executed. Used to load parameters
/// and update result location on completion.
///
///
/// The session context reconstructed by the SysJob worker from the
/// TSYSJOB row (ClientId, UserId, ServerConfigId etc.).
///
///
/// Cancellation token from the worker; triggered on job timeout or
/// explicit cancellation from the My Reports inbox.
///
///
/// The file path/URL stored in TSYSJOB.RESULTLOCATION on success.
/// Throws on unrecoverable failure — worker sets RUNSTATUS = Failed.
///
Task ExecuteAsyncJobAsync(
int sysJobId,
LoginDTO loginDTO,
CancellationToken cancellationToken = default);
// =====================================================================
// CONTEXT BUILDER — fluent helper for callers
// =====================================================================
///
/// Fluent builder to construct a
/// for a standard report (MMenu REPORTTYPE 1 or 2).
///
IReportContextBuilder ForStandardReport(
LoginDTO loginDTO,
int reportId,
int viewId = -1);
///
/// Fluent builder to construct a
/// for an analysis report (MMenu REPORTTYPE 0 or 3).
///
IReportContextBuilder ForAnalysisReport(
LoginDTO loginDTO,
int analysisId,
int queryId = -1);
}
// =========================================================================
// IReportContextBuilder — fluent builder interface
// =========================================================================
///
/// Fluent builder for .
/// Obtained via or
/// .
///
public interface IReportContextBuilder
{
///
/// Adds filter parameters. Accepts an anonymous object, a dictionary,
/// or any object serialisable to key-value pairs.
/// Existing parameters are merged (last-write-wins per key).
///
IReportContextBuilder WithParameters(object parameters);
///
/// Sets the requested export format.
/// Validated against MREPORTCONFIG.ALLOWEDEXPORTFORMATS at execution time.
/// Default: Grid.
///
IReportContextBuilder WithFormat(ExportFormat format);
///
/// Extracts and sets FromDate / ToDate from the parameters dictionary
/// for DateRangeDays calculation. Call after WithParameters.
/// Keys default to "FromDate" and "ToDate" — override if your report
/// uses different parameter names.
///
IReportContextBuilder WithDateRange(
string fromDateKey = "FromDate",
string toDateKey = "ToDate");
///
/// Sets the CancellationToken from the HTTP request.
/// Always call this: .WithCancellation(HttpContext.RequestAborted)
///
IReportContextBuilder WithCancellation(CancellationToken cancellationToken);
///
/// Explicitly overrides the DataSourceType, bypassing MREPORTCONFIG
/// and rule evaluation. Use sparingly — prefer metadata-driven routing.
/// Intended for admin/debug endpoints only.
///
IReportContextBuilder WithDataSourceOverride(DataSourceType dataSource);
/// Constructs and returns the immutable .
ReportExecutionContext Build();
}
// =========================================================================
// IReportEndpoint — contract every module report endpoint must satisfy
// =========================================================================
///
/// Contract for a module report endpoint. Implemented by module classes
/// that inherit FrameworkSL.ReportOrchestration.ReportEndpointBase.
/// The orchestrator calls after resolving
/// the connection and making the async/sync decision.
///
public interface IReportEndpoint
{
///
/// Fetches the flat report data rows for the given request context.
/// The connection is already open when this method is called.
/// Do not close or dispose it — the orchestrator manages lifetime.
///
System.Collections.Generic.IAsyncEnumerable> GetReportDataAsync(
ReportExecutionContext context,
System.Data.IDbConnection connection,
CancellationToken cancellationToken = default);
}
// =========================================================================
// IReportEndpointRegistry — discovery and lookup of module endpoints
// =========================================================================
///
/// Registry of all module report endpoint implementations.
/// Singleton — populated at startup by scanning module assemblies.
/// Used by to locate the correct endpoint.
///
public interface IReportEndpointRegistry
{
///
/// Locates the for the given report code.
/// Returns null when no endpoint is registered for this code.
///
IReportEndpoint? Resolve(string reportCode);
/// Returns all registered report codes.
System.Collections.Generic.IReadOnlyList GetRegisteredReportCodes();
}
// =========================================================================
// IAsyncDecisionEngine — injectable async/sync decision logic
// =========================================================================
///
/// Evaluates whether a report request should execute synchronously or be
/// submitted as a SysJob, based on AsyncMode, DateRangeDays, and policy.
/// Separated from the orchestrator so policy rules can be swapped/extended
/// without changing orchestration logic.
/// Registered as Scoped.
///
public interface IAsyncDecisionEngine
{
///
/// Returns true if the request should be submitted as a SysJob.
///
///
/// Decision logic by AsyncMode:
///
/// - Auto: true when DateRangeDays > AsyncThresholdDays.
/// - AlwaysAsync: always true.
/// - AlwaysSync: always false.
/// - PolicyBased: evaluates MREPORTPOLICY rules for
/// ClientId, RoleId, ModuleId, time-of-day. Falls back to
/// Auto if no policy matches.
///
///
///
/// Must have ReportConfig set (provides AsyncMode + AsyncThresholdDays).
///
/// Cancellation token for async operation.
Task ShouldRunAsyncAsync(
ReportExecutionContext context,
CancellationToken cancellationToken = default);
}
}