// =============================================================================
// GB5 Framework — ReportExecutionContext
// Namespace : GB5Shared.DTO.ReportOrchestration
// Purpose : The single DTO that flows through the entire orchestration
// pipeline. Carries identity, request parameters, resolved
// datasource, execution decisions, and result metadata.
// Created by QueryOrchestrator; read by all downstream layers.
// =============================================================================
using GB5Shared.DTO.Framework.Login;
using GB5Shared.Enums.ReportOrchestration;
namespace GB5Shared.DTO.ReportOrchestration
{
///
/// Central context object for a single report execution request.
/// Instantiated by and threaded through
/// connection resolution, execution, pivot, and export stages.
/// Immutable after construction except for fields set by the orchestrator
/// during pipeline stages (ResolvedDataSource, IsAsync, JobId, etc.).
///
public sealed class ReportExecutionContext
{
// ---------------------------------------------------------------------
// IDENTITY — who is requesting, for which report
// ---------------------------------------------------------------------
///
/// The authenticated session. Source of ClientId, UserId, RoleId,
/// ServerConfigId, DatabaseType, WorkDate, PeriodFromDate/ToDate.
/// Never null; set at construction.
///
public LoginDTO LoginDTO { get; init; } = null!;
///
/// The MREPORT.REPORTID being executed.
/// -1 for analysis reports (use AnalysisId instead).
///
public int ReportId { get; init; } = -1;
///
/// The MANALYSIS.ANALYSISID being executed.
/// -1 for standard reports (use ReportId instead).
///
public int AnalysisId { get; init; } = -1;
///
/// The specific MREPORTVIEW.REPORTVIEWID requested.
/// -1 means use the default view (ISDEFAULTVIEW = 0).
///
public int ReportViewId { get; init; } = -1;
///
/// Discriminates the call path so the orchestrator applies the
/// correct resolution, execution, and export strategy.
///
public ReportCallType CallType { get; init; } = ReportCallType.StandardReport;
// ---------------------------------------------------------------------
// REQUEST PARAMETERS — passed through to the module endpoint
// ---------------------------------------------------------------------
///
/// Report-specific filter parameters (date range, dimension filters,
/// free-text search etc.) as key-value pairs.
/// Forwarded as-is to the module endpoint via the HTTP request body.
/// The orchestrator reads FromDate / ToDate for async decisions.
///
public Dictionary Parameters { get; init; } = new();
///
/// Requested export format. Validated against
/// MREPORTCONFIG.ALLOWEDEXPORTFORMATS before execution.
///
public ExportFormat RequestedFormat { get; init; } = ExportFormat.Grid;
///
/// Convenience: FromDate extracted from Parameters["FromDate"].
/// Used for period-based async threshold calculation.
/// Null when not present or not applicable.
///
public DateTime? FromDate { get; init; }
///
/// Convenience: ToDate extracted from Parameters["ToDate"].
/// Used for period-based async threshold calculation.
/// Null when not present or not applicable.
///
public DateTime? ToDate { get; init; }
///
/// Date range in days between FromDate and ToDate.
/// Returns 0 when either date is absent.
/// Used by AsyncMode.Auto threshold evaluation.
///
public int DateRangeDays =>
(FromDate.HasValue && ToDate.HasValue)
? Math.Max(0, (int)(ToDate.Value.Date - FromDate.Value.Date).TotalDays)
: 0;
// ---------------------------------------------------------------------
// RESOLVED CONFIGURATION — set by orchestrator after loading MREPORTCONFIG
// ---------------------------------------------------------------------
///
/// The MREPORTCONFIG loaded for this report.
/// Null for analysis reports or when config is not yet loaded.
///
public ReportConfigDTO? ReportConfig { get; set; }
///
/// The final resolved DataSourceType after applying
/// MREPORTCONFIG.DATASOURCETYPE and any matching MREPORTDATASOURCERULE.
/// Set by the orchestrator's source resolution stage.
///
public DataSourceType ResolvedDataSource { get; set; } = DataSourceType.Oltp;
///
/// The resolved server configuration for the chosen DataSourceType.
/// Set by .
/// Contains the connection string and provider type — never serialised.
///
public ReportServerConfigDTO? ResolvedServerConfig { get; set; }
// ---------------------------------------------------------------------
// EXECUTION DECISIONS — set by orchestrator before execution
// ---------------------------------------------------------------------
///
/// True when this request will be executed asynchronously via SysJob.
/// Determined by AsyncMode + DateRangeDays + policy evaluation.
///
public bool IsAsync { get; set; }
///
/// The SysJob SYSJOBID submitted for async execution.
/// -1 when IsAsync = false or before SysJob submission.
///
public int SysJobId { get; set; } = -1;
///
/// Query execution timeout in seconds.
/// Sourced from MREPORTCONFIG.QUERYTIMEOUTSECONDS.
/// Sync default: 30s. Async default: 300s.
///
public int QueryTimeoutSeconds { get; set; } = 30;
///
/// When true and DataSource is ReportDB or ArchiveDB on SQL Server,
/// the orchestrator appends NOLOCK hints via query wrapper.
/// Sourced from MREPORTCONFIG.ISNOLOCKALLOWED.
/// Always false for OLTP writes and Oracle/PostgreSQL.
///
public bool ApplyNoLock { get; set; }
///
/// CancellationToken propagated from the HTTP request through the
/// full execution pipeline (connection open, query, export).
/// Allows browser-cancel to abort long-running queries.
///
public CancellationToken CancellationToken { get; init; } = CancellationToken.None;
// ---------------------------------------------------------------------
// TRACING — for diagnostics and audit
// ---------------------------------------------------------------------
///
/// Unique identifier for this execution request.
/// Used to correlate log entries across all pipeline stages.
///
public Guid CorrelationId { get; init; } = Guid.NewGuid();
///
/// UTC timestamp when this context was created (request received).
///
public DateTime RequestedAtUtc { get; init; } = DateTime.UtcNow;
}
// =========================================================================
// ReportConfigDTO — subset of MREPORTCONFIG columns loaded by orchestrator
// =========================================================================
///
/// Projection of MREPORTCONFIG loaded by the orchestrator.
/// Only the fields needed for execution decisions are included.
/// Full MREPORTCONFIG entity lives in the DAL layer.
///
public sealed class ReportConfigDTO
{
public int ReportConfigId { get; init; }
public int ReportId { get; init; }
/// Configured datasource preference before rule evaluation.
public DataSourceType DataSourceType { get; init; } = DataSourceType.Oltp;
/// Controls sync vs async execution decision.
public AsyncMode AsyncMode { get; init; } = AsyncMode.Auto;
///
/// When AsyncMode = Auto, requests with DateRangeDays exceeding this
/// threshold are submitted as SysJob. Default: 90 days.
///
public int AsyncThresholdDays { get; init; } = 90;
/// Sync query timeout in seconds. Default: 30.
public int QueryTimeoutSeconds { get; init; } = 30;
/// Async (SysJob) query timeout in seconds. Default: 300.
public int AsyncQueryTimeoutSeconds { get; init; } = 300;
///
/// Minutes to cache the result. 0 = no cache.
/// Cache key includes ReportId + CacheKeyParams + ClientId.
///
public int CacheDurationMinutes { get; init; }
///
/// Comma-separated parameter names that form part of the cache key.
/// Null = all parameters included in cache key.
///
public string? CacheKeyParams { get; init; }
/// Default export format for this report.
public ExportFormat DefaultExportFormat { get; init; } = ExportFormat.Grid;
///
/// Comma-separated ExportFormat byte values that are allowed.
/// e.g. "0,1,2" = Grid, PDF, Excel only.
///
public string AllowedExportFormats { get; init; } = "0,1,2,3";
/// Where pivot transformation occurs.
public PivotEngine PivotEngine { get; init; } = PivotEngine.None;
/// Semantic category for UI grouping and default suggestions.
public ReportCategory ReportCategory { get; init; } = ReportCategory.Operational;
///
/// Whether NOLOCK hints may be applied when routing to ReportDB/ArchiveDB.
/// Only honoured on SQL Server. False for Oracle/PostgreSQL.
///
public bool IsNoLockAllowed { get; init; }
/// SysJob result file TTL in hours. Default: 24.
public int ResultExpiryHours { get; init; } = 24;
/// SysJob priority (1–10). Higher = executed first.
public byte DefaultPriority { get; init; } = 5;
///
/// Optional COUNT query used by RuleType=1 (EstimatedRows) to decide
/// whether to route to ReportDB or ArchiveDB. Null means no estimation query configured.
///
public string? EstimationQuery { get; init; }
}
}