using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using Microsoft.AspNetCore.SignalR; using MMBLL.Scheduling; using MMDAL.DTO.Scheduling; using MMSL.Hubs; using static GB5Shared.GB5Constant.Constant; namespace MMSL.Services { // Registered as Singleton — receives Dapr pub/sub messages on "schedulingrun.trigger" topic. // Uses IServiceScopeFactory because it needs scoped BLL services per message. public class SchedulingRunProcessingService { private readonly IServiceScopeFactory _ScopeFactory; private readonly IHubContext _HubContext; private readonly ILogger _Logger; public SchedulingRunProcessingService( IServiceScopeFactory scopeFactory, IHubContext hubContext, ILogger logger) { _ScopeFactory = scopeFactory; _HubContext = hubContext; _Logger = logger; } public async Task ProcessAsync(SchedulingRunTriggerDTO trigger, CancellationToken ct = default) { var group = SchedulingRunHub.HubGroup(trigger.WorkOUId); var login = new LoginDTO { ClientId = trigger.TenantId, WorkOUId = trigger.WorkOUId, UserId = trigger.UserId }; using var scope = _ScopeFactory.CreateScope(); var autoNumber = scope.ServiceProvider.GetRequiredService(); var auto = await autoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.SCHEDULINGRUN, login); int schedulingRunId = auto.StartNumber; var bll = scope.ServiceProvider.GetRequiredService(); // Wire IProgress → SignalR ReceiveProgress push var progress = new Progress(async report => { try { await _HubContext.Clients.Group(group) .ReceiveProgress(report.Percent, report.Step, report.CurrentItem); } catch (Exception ex) { _Logger.LogWarning(ex, "SignalR push failed for group {Group}", group); } }); try { var summary = await bll.ProcessSchedulingRunAsync(trigger, schedulingRunId, login, progress, ct) .ConfigureAwait(false); // RCCP warnings pushed during run; emit complete at the end foreach (var warning in summary.RCCPWarnings) await _HubContext.Clients.Group(group).ReceiveWarning(warning); await _HubContext.Clients.Group(group).ReceiveComplete(schedulingRunId, summary); } catch (Exception ex) { _Logger.LogError(ex, "Scheduling run {RunId} failed", schedulingRunId); await _HubContext.Clients.Group(group) .ReceiveError($"Scheduling run failed: {ex.Message}"); } } public async Task ProcessAsyncWithLogin(SchedulingRunTriggerDTO trigger,LoginDTO login,CancellationToken ct = default) { var group = SchedulingRunHub.HubGroup(trigger.WorkOUId); using var scope = _ScopeFactory.CreateScope(); var autoNumber = scope.ServiceProvider.GetRequiredService(); var auto = await autoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.SCHEDULINGRUN, login); int schedulingRunId = auto.StartNumber; var bll = scope.ServiceProvider.GetRequiredService(); // Wire IProgress → SignalR ReceiveProgress push var progress = new Progress(async report => { try { await _HubContext.Clients.Group(group) .ReceiveProgress(report.Percent, report.Step, report.CurrentItem); } catch (Exception ex) { _Logger.LogWarning(ex, "SignalR push failed for group {Group}", group); } }); try { var summary = await bll.ProcessSchedulingRunAsync(trigger, schedulingRunId, login, progress, ct) .ConfigureAwait(false); // RCCP warnings pushed during run; emit complete at the end foreach (var warning in summary.RCCPWarnings) await _HubContext.Clients.Group(group).ReceiveWarning(warning); await _HubContext.Clients.Group(group).ReceiveComplete(schedulingRunId, summary); } catch (Exception ex) { _Logger.LogError(ex, "Scheduling run {RunId} failed", schedulingRunId); await _HubContext.Clients.Group(group) .ReceiveError($"Scheduling run failed: {ex.Message}"); } } } }