using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using FrameworkDAL.CustomCode.GOP; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.GOP; using GB5Shared.Resource.Response; using Microsoft.Extensions.Logging; namespace FrameworkBLL.GOP { // ============================================================ // GopExecutionMonitorBLL — read-only view of GOP runtime data. // // This BLL is intentionally thin: it delegates to IGopQueueDAL // and IGopFlowDAL without adding business logic. // The only write operation here is ResolveRemediation, which marks a // remediation item Resolved -- it does NOT re-queue/resubmit the original // failed execution (there is no automatic link back to it). To actually // retry a failed execution, call ReplayGopExecution (GopQueueBLL) with its // ExecutionId separately. // ============================================================ public class GopExecutionMonitorBLL : IGopExecutionMonitorBLL { private readonly IGopQueueDAL _QueueDal; private readonly ILogger _Logger; public GopExecutionMonitorBLL( IGopQueueDAL queueDal, ILogger logger) { _QueueDal = queueDal; _Logger = logger; } // ── Execution ───────────────────────────────────────────────────────────── public async Task> GetExecutionList( string? status, int page, int pageSize, LoginDTO loginDTO, CancellationToken ct = default) { int safePageSize = Math.Clamp(pageSize, 1, 200); int safePage = Math.Max(1, page); return await _QueueDal.GetExecutionsByStatus( loginDTO.ClientId, status, safePage, safePageSize, loginDTO); } public async Task GetExecutionDetail( int executionId, LoginDTO loginDTO, CancellationToken ct = default) { return await _QueueDal.GetExecutionById(loginDTO.ClientId, executionId, loginDTO); } public async Task> GetExecutionNodeLogs( int executionId, LoginDTO loginDTO, CancellationToken ct = default) { return await _QueueDal.GetNodeLogsByExecution(loginDTO.ClientId, executionId, loginDTO); } public async Task> GetExecutionStateLogs( int executionId, LoginDTO loginDTO, CancellationToken ct = default) { return await _QueueDal.GetStateLogsByExecution(loginDTO.ClientId, executionId, loginDTO); } // ── Dead Letter Queue ───────────────────────────────────────────────────── public async Task> GetDeadLetterList( LoginDTO loginDTO, CancellationToken ct = default) { return await _QueueDal.GetDeadLetters(loginDTO.ClientId, loginDTO); } // ── Remediation ─────────────────────────────────────────────────────────── public async Task> GetOpenRemediations( LoginDTO loginDTO, CancellationToken ct = default) { return await _QueueDal.GetOpenRemediations(loginDTO.ClientId, loginDTO); } public async Task ResolveRemediation( int remediationId, string resolutionNotes, LoginDTO loginDTO, CancellationToken ct = default) { if (remediationId == 0) throw new ArgumentException("RemediationId is required."); if (string.IsNullOrWhiteSpace(resolutionNotes)) throw new ArgumentException("ResolutionNotes are required."); await _QueueDal.UpdateRemediation( loginDTO.ClientId, remediationId, "Resolved", resolutionNotes, loginDTO.UserId.ToString(), loginDTO); _Logger.LogInformation( "GopExecutionMonitorBLL: remediation {RemediationId} resolved by user {UserId}", remediationId, loginDTO.UserId); return $"{SuccessResponse.UpdateSuccessMessage} {remediationId}"; } // ── Dashboard ───────────────────────────────────────────────────────────── public async Task> GetQueueDashboard( LoginDTO loginDTO, CancellationToken ct = default) { return await _QueueDal.GetQueueDashboard(loginDTO.ClientId, loginDTO); } } }