using System.Text.Json; using HrynCo.NotificationService.DAL.Abstract.Providers; using HrynCo.NotificationService.DAL.Abstract.Repositories; using HrynCo.DAL.EF.Core; using HrynCo.NotificationService.DAL.EF.Entities; using Microsoft.EntityFrameworkCore; namespace HrynCo.NotificationService.DAL.EF.Repositories; internal sealed class EmailChannelRepository : EfRepository, IEmailChannelRepository { public EmailChannelRepository(NotificationDbContext dbContext) : base(dbContext) { } public async Task> GetAllAsync(CancellationToken ct = default) { var entities = await DbSet .AsNoTracking() .OrderBy(x => x.ServiceName) .ThenBy(x => x.Priority) .ToListAsync(ct); return entities.Select(MapToDomain).ToList(); } public async Task> GetByServiceAsync(string serviceName, CancellationToken ct = default) { var entities = await DbSet .AsNoTracking() .Where(x => x.ServiceName == serviceName) .OrderBy(x => x.Priority) .ToListAsync(ct); return entities.Select(MapToDomain).ToList(); } public async Task> GetAllWithUsageSummaryAsync( DateOnly today, CancellationToken ct = default) { var rows = await DbSet .AsNoTracking() .OrderBy(c => c.ServiceName) .ThenBy(c => c.Priority) .Select(c => new { Channel = c, DailySent = c.UsageRecords .Where(u => u.Date == today) .Sum(u => (int?)u.SentCount) ?? 0, MonthlySent = c.UsageRecords .Where(u => u.Date.Year == today.Year && u.Date.Month == today.Month) .Sum(u => (int?)u.SentCount) ?? 0 }) .ToListAsync(ct); return rows .Select(r => new ChannelWithUsage(MapToDomain(r.Channel), r.DailySent, r.MonthlySent)) .ToList(); } public async Task GetByIdAsync(Guid id, CancellationToken ct = default) { EmailChannelEntity? entity = await DbSet.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, ct); return entity is null ? null : MapToDomain(entity); } public Task AddAsync(EmailChannel channel, CancellationToken ct = default) { return base.AddAsync(MapToEntity(channel), ct); } public Task UpdateAsync(EmailChannel channel, CancellationToken ct = default) { EmailChannelEntity entity = MapToEntity(channel); entity.Updated = DateTimeOffset.UtcNow; Update(entity); return Task.CompletedTask; } public async Task DeleteAsync(EmailChannel channel, CancellationToken ct = default) { EmailChannelEntity? entity = await DbSet.FindAsync([channel.Id], ct); if (entity is not null) { Delete(entity); } } private static EmailChannel MapToDomain(EmailChannelEntity e) { return new EmailChannel { Id = e.Id, ServiceName = e.ServiceName, Priority = e.Priority, EmailChannelType = e.EmailChannelType, Settings = DeserializeSettings(e.EmailChannelType, e.SettingsJson), DailyLimit = e.DailyLimit, MonthlyLimit = e.MonthlyLimit, WarnThresholdPercent = e.WarnThresholdPercent, IsActive = e.IsActive, Created = e.Created, Updated = e.Updated }; } private static EmailChannelEntity MapToEntity(EmailChannel p) { return new EmailChannelEntity { Id = p.Id, ServiceName = p.ServiceName, Priority = p.Priority, EmailChannelType = p.EmailChannelType, SettingsJson = JsonSerializer.Serialize(p.Settings, p.Settings.GetType()), DailyLimit = p.DailyLimit, MonthlyLimit = p.MonthlyLimit, WarnThresholdPercent = p.WarnThresholdPercent, IsActive = p.IsActive, Created = p.Created, Updated = p.Updated }; } private static EmailChannelSettings DeserializeSettings(EmailChannelType type, string json) { return type switch { EmailChannelType.Smtp => JsonSerializer.Deserialize(json) ?? throw new InvalidOperationException( "Failed to deserialize SMTP EmailChannel settings."), _ => throw new InvalidOperationException($"Unknown or undefined email channel type: {type}") }; } }