using System; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using RecruitmentBLL.Common; namespace RecruitmentSL.Hubs { // Concrete implementation of the BLL-defined IRecruitmentHubNotifier, wrapping // IHubContext — this is the one place in this module // allowed to know about SignalR, per CLAUDE.md's "BLL must never reference ASP.NET types" // rule. Registered as a Scoped/Singleton service in RecruitmentSL/Program.cs (IHubContext // itself is a thread-safe singleton). Mirrors WiSL.EndPoints.Hubs.WiHubNotifier / // DXPSL.Hubs.DXPHubNotifier exactly. public class RecruitmentHubNotifier : IRecruitmentHubNotifier { private readonly IHubContext _hubContext; private readonly ILogger _logger; public RecruitmentHubNotifier( IHubContext hubContext, ILogger logger) { _hubContext = hubContext; _logger = logger; } public async Task NotifyApplicationStageChangedAsync( int applicationId, int jobRequisitionId, int oldSelectionProcessStageId, int newSelectionProcessStageId, int clientId, CancellationToken ct = default) { try { var update = new ApplicationStageChangedDTO { ApplicationId = applicationId, JobRequisitionId = jobRequisitionId, OldSelectionProcessStageId = oldSelectionProcessStageId, NewSelectionProcessStageId = newSelectionProcessStageId, ChangedOn = DateTime.UtcNow }; await _hubContext.Clients.Group(RecruitmentHub.ClientGroup(clientId)) .ReceiveApplicationStageChanged(update); } catch (Exception ex) { _logger.LogWarning(ex, "RecruitmentHubNotifier: failed to push stage change for ApplicationId {ApplicationId}", applicationId); } } public async Task NotifyInterviewScheduledAsync( int interviewId, int applicationId, int interviewerId, DateTime interviewDate, short interviewTime, short durationMinutes, bool isReschedule, CancellationToken ct = default) { try { var update = new InterviewScheduledDTO { InterviewId = interviewId, ApplicationId = applicationId, InterviewerId = interviewerId, InterviewDate = interviewDate, InterviewTime = interviewTime, DurationMinutes = durationMinutes, IsReschedule = isReschedule }; await _hubContext.Clients.Group(RecruitmentHub.UserGroup(interviewerId)) .ReceiveInterviewScheduled(update); } catch (Exception ex) { _logger.LogWarning(ex, "RecruitmentHubNotifier: failed to push interview scheduled for InterviewId {InterviewId}", interviewId); } } } }