using AutoMapper; using GreenHome.Application; using GreenHome.Infrastructure.Data; using Microsoft.EntityFrameworkCore; namespace GreenHome.Infrastructure.Services.Device; public sealed class DeviceSettingsService : IDeviceSettingsService { private readonly GreenHomeDbContext _dbContext; private readonly IMapper _mapper; public DeviceSettingsService(GreenHomeDbContext dbContext, IMapper mapper) { _dbContext = dbContext; _mapper = mapper; } public async Task GetByDeviceIdAsync(int deviceId, CancellationToken cancellationToken) { var settings = await _dbContext.DeviceSettings .Include(x => x.Device) .Include(x => x.Relays) .ThenInclude(r => r.Rules) .AsNoTracking() .FirstOrDefaultAsync(x => x.DeviceId == deviceId, cancellationToken); if (settings == null) return null; var dto = _mapper.Map(settings); OrderRelays(dto); return dto; } public async Task CreateAsync(DeviceSettingsDto dto, CancellationToken cancellationToken) { var entity = _mapper.Map(dto); entity.CreatedAt = DateTime.UtcNow; entity.UpdatedAt = DateTime.UtcNow; SyncRelays(entity, dto.Relays ?? new List()); _dbContext.DeviceSettings.Add(entity); await _dbContext.SaveChangesAsync(cancellationToken); return entity.Id; } public async Task UpdateAsync(DeviceSettingsDto dto, CancellationToken cancellationToken) { var entity = await _dbContext.DeviceSettings .Include(x => x.Relays) .ThenInclude(r => r.Rules) .FirstOrDefaultAsync(x => x.DeviceId == dto.DeviceId, cancellationToken); if (entity == null) throw new InvalidOperationException($"Device settings not found for device ID {dto.DeviceId}"); _mapper.Map(dto, entity); entity.UpdatedAt = DateTime.UtcNow; SyncRelays(entity, dto.Relays ?? new List()); await _dbContext.SaveChangesAsync(cancellationToken); } private static void OrderRelays(DeviceSettingsDto dto) { if (dto.Relays == null) return; dto.Relays = dto.Relays .OrderBy(r => r.RelayIndex) .ToList(); foreach (var relay in dto.Relays) { relay.Rules = relay.Rules? .OrderBy(r => r.Order) .ToList() ?? new List(); } } private static void SyncRelays(Domain.DeviceSettings entity, List relayDtos) { var now = DateTime.UtcNow; var dtoIndexes = relayDtos.Select(r => r.RelayIndex).ToHashSet(); // حذف رله‌هایی که دیگر در لیست نیستند foreach (var relay in entity.Relays.Where(r => !dtoIndexes.Contains(r.RelayIndex)).ToList()) { entity.Relays.Remove(relay); } foreach (var dto in relayDtos) { var relay = entity.Relays.FirstOrDefault(r => r.RelayIndex == dto.RelayIndex); if (relay == null) { relay = new Domain.DeviceRelay { RelayIndex = dto.RelayIndex, CreatedAt = now }; entity.Relays.Add(relay); } relay.Name = dto.Name ?? string.Empty; relay.IsEnabled = dto.IsEnabled; relay.RelayKind = dto.RelayKind; relay.Mode = dto.Mode; relay.MinOnMinutes = dto.MinOnMinutes; relay.MinOffMinutes = dto.MinOffMinutes; relay.UpdatedAt = now; SyncRules(relay, dto.Rules ?? new List()); } } private static void SyncRules(Domain.DeviceRelay relay, List ruleDtos) { relay.Rules.Clear(); foreach (var dto in ruleDtos.OrderBy(r => r.Order)) { relay.Rules.Add(new Domain.RelayRule { SensorType = dto.SensorType, ComparisonType = dto.ComparisonType, Value1 = dto.Value1, Value2 = dto.Value2, Action = dto.Action, TimeType = dto.TimeType, Order = dto.Order }); } } }