using AutoMapper; using GreenHome.Application; using GreenHome.Infrastructure.Data; using Microsoft.EntityFrameworkCore; namespace GreenHome.Infrastructure.Services.Alert; public sealed class AlertConditionService : IAlertConditionService { private readonly GreenHomeDbContext _dbContext; private readonly IMapper _mapper; public AlertConditionService(GreenHomeDbContext dbContext, IMapper mapper) { _dbContext = dbContext; _mapper = mapper; } public async Task> GetByDeviceIdAsync(int deviceId, CancellationToken cancellationToken) { var conditions = await _dbContext.AlertConditions .Include(x => x.Device) .Include(x => x.Rules) .Where(x => x.DeviceId == deviceId) .OrderByDescending(x => x.CreatedAt) .AsNoTracking() .ToListAsync(cancellationToken); return _mapper.Map>(conditions); } public async Task GetByIdAsync(int id, CancellationToken cancellationToken) { var condition = await _dbContext.AlertConditions .Include(x => x.Device) .Include(x => x.Rules) .AsNoTracking() .FirstOrDefaultAsync(x => x.Id == id, cancellationToken); return condition != null ? _mapper.Map(condition) : null; } public async Task CreateAsync(CreateAlertConditionRequest request, CancellationToken cancellationToken) { var condition = new Domain.AlertCondition { DeviceId = request.DeviceId, NotificationType = request.NotificationType, TimeType = request.TimeType, CallCooldownMinutes = request.CallCooldownMinutes, SmsCooldownMinutes = request.SmsCooldownMinutes, IsEnabled = request.IsEnabled, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; var rules = _mapper.Map>(request.Rules); foreach (var rule in rules) { condition.Rules.Add(rule); } _dbContext.AlertConditions.Add(condition); await _dbContext.SaveChangesAsync(cancellationToken); return condition.Id; } public async Task UpdateAsync(UpdateAlertConditionRequest request, CancellationToken cancellationToken) { var condition = await _dbContext.AlertConditions .Include(x => x.Rules) .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken); if (condition == null) throw new InvalidOperationException($"Alert condition not found: {request.Id}"); condition.NotificationType = request.NotificationType; condition.TimeType = request.TimeType; condition.CallCooldownMinutes = request.CallCooldownMinutes; condition.SmsCooldownMinutes = request.SmsCooldownMinutes; condition.IsEnabled = request.IsEnabled; condition.UpdatedAt = DateTime.UtcNow; _dbContext.AlertRules.RemoveRange(condition.Rules); condition.Rules.Clear(); var newRules = _mapper.Map>(request.Rules); foreach (var rule in newRules) { condition.Rules.Add(rule); } await _dbContext.SaveChangesAsync(cancellationToken); } public async Task DeleteAsync(int id, CancellationToken cancellationToken) { var condition = await _dbContext.AlertConditions .FirstOrDefaultAsync(x => x.Id == id, cancellationToken); if (condition == null) throw new InvalidOperationException($"Alert condition not found: {id}"); _dbContext.AlertConditions.Remove(condition); await _dbContext.SaveChangesAsync(cancellationToken); } public async Task ToggleEnabledAsync(int id, bool isEnabled, CancellationToken cancellationToken) { var condition = await _dbContext.AlertConditions .FirstOrDefaultAsync(x => x.Id == id, cancellationToken); if (condition == null) return false; condition.IsEnabled = isEnabled; condition.UpdatedAt = DateTime.UtcNow; await _dbContext.SaveChangesAsync(cancellationToken); return true; } public async Task> GetRelayConditionsAsync(int deviceId, CancellationToken cancellationToken) { var conditions = await _dbContext.AlertConditions .Include(x => x.Rules) .Where(x => x.DeviceId == deviceId && (int)x.NotificationType > 0) .OrderByDescending(x => x.CreatedAt) .AsNoTracking() .ToListAsync(cancellationToken); var result = conditions.Select(c => new RelayConditionDto { Enabled = c.IsEnabled ? 1 : 0, TimeType = (int)c.TimeType, Relay = "R" + (int)c.NotificationType, Rules = c.Rules.OrderBy(r => r.Order).Select(r => new RelayRuleDto { Sensor = ((int)r.SensorType).ToString(), Op = ((int)r.ComparisonType).ToString(), V1 = r.Value1, V2 = r.Value2 }).ToList() }).ToList(); return result; } public async Task> GetUpdatedRelayConditionsAsync(int deviceId, DateTime? lastUpdateDate, CancellationToken cancellationToken) { if (lastUpdateDate == null) return await GetRelayConditionsAsync(deviceId, cancellationToken); var hasUpdates = await _dbContext.AlertConditions .AnyAsync(x => x.DeviceId == deviceId && (int)x.NotificationType > 0 && x.UpdatedAt > lastUpdateDate, cancellationToken); if (!hasUpdates) return Array.Empty(); return await GetRelayConditionsAsync(deviceId, cancellationToken); } public async Task HasUpdatedConditionsAsync(int deviceId, DateTime? lastUpdateDate, CancellationToken cancellationToken) { if (lastUpdateDate == null) return true; return await _dbContext.AlertConditions .AnyAsync(x => x.DeviceId == deviceId && (int)x.NotificationType > 0 && x.UpdatedAt > lastUpdateDate, cancellationToken); } }