using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using PowderCoating.Application.DTOs.Common; using PowderCoating.Application.DTOs.Notification; using PowderCoating.Core.Enums; using PowderCoating.Core.Interfaces; using PowderCoating.Shared.Constants; namespace PowderCoating.Web.Controllers; /// /// Company-scoped notification log viewer accessible to users with the /// CanManageJobs policy (Managers and above within a company). /// The platform-wide equivalent for SuperAdmins lives in /// . /// [Authorize(Policy = AppConstants.Policies.CanManageJobs)] public class NotificationLogsController : Controller { private readonly IUnitOfWork _unitOfWork; private readonly ILogger _logger; public NotificationLogsController(IUnitOfWork unitOfWork, ILogger logger) { _unitOfWork = unitOfWork; _logger = logger; } /// /// Displays a paginated, filterable list of notification log entries for the current company. /// Supports filtering by free-text search, channel, delivery status, notification type, and /// an optional job context. Page size is validated against an allowlist (10/25/50/100). /// // GET: /NotificationLogs public async Task Index( string? searchTerm, string? channelFilter, string? statusFilter, string? typeFilter, int? jobId, string? sortColumn, string sortDirection = "desc", int pageNumber = 1, int pageSize = 25) { pageNumber = Math.Max(1, pageNumber); pageSize = pageSize is 10 or 25 or 50 or 100 ? pageSize : 25; NotificationChannel? channel = Enum.TryParse(channelFilter, out var ch) ? ch : null; NotificationStatus? status = Enum.TryParse(statusFilter, out var st) ? st : null; NotificationType? type = Enum.TryParse(typeFilter, out var ty) ? ty : null; var (logs, totalCount) = await _unitOfWork.NotificationLogs.GetPagedFilteredAsync( pageNumber, pageSize, searchTerm, channel, status, type, jobId, sortColumn ?? "SentAt", sortDirection); var items = logs.Select(n => new NotificationLogDto { Id = n.Id, Channel = n.Channel, NotificationType = n.NotificationType, Status = n.Status, RecipientName = n.RecipientName, Recipient = n.Recipient, Subject = n.Subject, Message = n.Message, ErrorMessage = n.ErrorMessage, SentAt = n.SentAt, CustomerId = n.CustomerId, JobId = n.JobId, QuoteId = n.QuoteId, JobNumber = n.Job?.JobNumber, QuoteNumber = n.Quote?.QuoteNumber, CustomerName = n.Customer != null ? (n.Customer.CompanyName ?? $"{n.Customer.ContactFirstName} {n.Customer.ContactLastName}".Trim()) : null }).ToList(); var pagedResult = new PagedResult { Items = items, TotalCount = totalCount, PageNumber = pageNumber, PageSize = pageSize }; ViewBag.SearchTerm = searchTerm; ViewBag.ChannelFilter = channelFilter; ViewBag.StatusFilter = statusFilter; ViewBag.TypeFilter = typeFilter; ViewBag.JobId = jobId; ViewBag.SortColumn = sortColumn ?? "SentAt"; ViewBag.SortDirection = sortDirection; return View(pagedResult); } /// /// Displays the full details of a single notification log entry including the complete message /// body and any error message, which are omitted from the list view. Loads related Customer, /// Job, and Quote navigation properties to resolve display names. /// // GET: /NotificationLogs/Details/5 public async Task Details(int id) { try { var log = await _unitOfWork.NotificationLogs.GetByIdAsync( id, false, n => n.Customer, n => n.Job, n => n.Quote); if (log == null) return NotFound(); var dto = new NotificationLogDto { Id = log.Id, Channel = log.Channel, NotificationType = log.NotificationType, Status = log.Status, RecipientName = log.RecipientName, Recipient = log.Recipient, Subject = log.Subject, Message = log.Message, ErrorMessage = log.ErrorMessage, SentAt = log.SentAt, CustomerId = log.CustomerId, JobId = log.JobId, QuoteId = log.QuoteId, JobNumber = log.Job?.JobNumber, QuoteNumber = log.Quote?.QuoteNumber, CustomerName = log.Customer != null ? (log.Customer.CompanyName ?? $"{log.Customer.ContactFirstName} {log.Customer.ContactLastName}".Trim()) : null }; return View(dto); } catch (Exception ex) { _logger.LogError(ex, "Error loading notification log {Id}", id); return RedirectToAction(nameof(Index)); } } }