using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; using SPMS.Domain.Entities; using SPMS.Domain.Enums; using SPMS.Domain.Interfaces; namespace SPMS.Infrastructure.Persistence.Repositories; public class MessageRepository : Repository, IMessageRepository { public MessageRepository(AppDbContext context) : base(context) { } public async Task GetByMessageCodeAsync(string messageCode) { return await _dbSet .FirstOrDefaultAsync(m => m.MessageCode == messageCode && !m.IsDeleted); } public async Task GetByMessageCodeAndServiceAsync(string messageCode, long serviceId) { return await _dbSet .FirstOrDefaultAsync(m => m.MessageCode == messageCode && m.ServiceId == serviceId && !m.IsDeleted); } public async Task GetTodaySequenceAsync(long serviceId) { var todayStart = DateTime.UtcNow.Date; var todayEnd = todayStart.AddDays(1); return await _dbSet .CountAsync(m => m.ServiceId == serviceId && m.CreatedAt >= todayStart && m.CreatedAt < todayEnd); } public async Task<(IReadOnlyList Items, int TotalCount)> GetPagedByServiceAsync( long serviceId, int page, int size, Expression>? predicate = null) { var query = _dbSet .Where(m => m.ServiceId == serviceId && !m.IsDeleted); if (predicate != null) query = query.Where(predicate); var totalCount = await query.CountAsync(); var items = await query .OrderByDescending(m => m.CreatedAt) .Skip((page - 1) * size) .Take(size) .ToListAsync(); return (items, totalCount); } public async Task GetByMessageCodeWithDetailsAsync(string messageCode, long serviceId) { return await _dbSet .Include(m => m.Service) .Include(m => m.CreatedByAdmin) .FirstOrDefaultAsync(m => m.MessageCode == messageCode && m.ServiceId == serviceId && !m.IsDeleted); } public async Task<(int TotalSendCount, int SuccessCount)> GetSendStatsAsync(long messageId) { var stats = await _context.PushSendLogs .Where(l => l.MessageId == messageId) .GroupBy(_ => 1) .Select(g => new { Total = g.Count(), Success = g.Count(l => l.Status == PushResult.Success) }) .FirstOrDefaultAsync(); return stats != null ? (stats.Total, stats.Success) : (0, 0); } public async Task<(IReadOnlyList Items, int TotalCount)> GetPagedForListAsync( long? serviceId, int page, int size, string? keyword = null, bool? isActive = null, string? sendStatus = null) { var query = _dbSet.Where(m => !m.IsDeleted); if (serviceId.HasValue) query = query.Where(m => m.ServiceId == serviceId.Value); if (!string.IsNullOrWhiteSpace(keyword)) query = query.Where(m => m.Title.Contains(keyword) || m.Body.Contains(keyword)); if (isActive.HasValue) query = query.Where(m => m.IsDeleted != isActive.Value); var projected = query.Select(m => new MessageListProjection { MessageCode = m.MessageCode, Title = m.Title, IsActive = !m.IsDeleted, CreatedAt = m.CreatedAt, ServiceName = m.Service.ServiceName, ServiceCode = m.Service.ServiceCode, TotalSendCount = _context.PushSendLogs.Count(l => l.MessageId == m.Id), SuccessCount = _context.PushSendLogs.Count(l => l.MessageId == m.Id && l.Status == PushResult.Success) }); // 발송 상태 필터 if (sendStatus == "complete") projected = projected.Where(p => p.SuccessCount > 0); else if (sendStatus == "failed") projected = projected.Where(p => p.TotalSendCount > 0 && p.SuccessCount == 0); else if (sendStatus == "pending") projected = projected.Where(p => p.TotalSendCount == 0); var totalCount = await projected.CountAsync(); var items = await projected .OrderByDescending(p => p.CreatedAt) .Skip((page - 1) * size) .Take(size) .ToListAsync(); return (items, totalCount); } }