using Fitness_core_BE.Interfaces; using Fitness_core_BE.Models; using Microsoft.EntityFrameworkCore; namespace Fitness_core_BE.Repos { public class DeviceCommandRepo : IDeviceCommandRepo { private readonly TenantDbContext _dbContext; public DeviceCommandRepo(TenantDbContext dbContext) { _dbContext = dbContext; } public async Task AddAsync(DeviceCommand command) { await _dbContext.DeviceCommands.AddAsync(command); return command; } public async Task> GetPendingByClientAsync(Guid clientId) { return await _dbContext.DeviceCommands .Where(c => c.FKClientId == clientId && c.Status == "Pending") .OrderBy(c => c.CreatedAt) .ToListAsync(); } public async Task GetByIdAsync(Guid commandId) { return await _dbContext.DeviceCommands .FirstOrDefaultAsync(c => c.Id == commandId); } public Task IsQueuedAsync( Guid bindingId, string commandType, int desiredVersion, CancellationToken ct = default) { return _dbContext.DeviceCommands.AnyAsync(command => command.FKAccessDeviceBindingId == bindingId && command.CommandType == commandType && command.DesiredVersion == desiredVersion && (command.Status == "Pending" || command.Status == "InProgress"), ct); } public Task> GetPendingStateCommandsAsync( Guid bindingId, CancellationToken ct = default) { return _dbContext.DeviceCommands .Where(command => command.FKAccessDeviceBindingId == bindingId && command.CommandType == "SetAccessState" && command.Status == "Pending") .ToListAsync(ct); } public Task> GetPendingFacePhotoCommandsAsync( Guid bindingId, CancellationToken ct = default) { return _dbContext.DeviceCommands .Where(command => command.FKAccessDeviceBindingId == bindingId && command.CommandType == "UpsertFacePhoto" && command.Status == "Pending") .ToListAsync(ct); } public Task> GetExhaustedLeasesAsync( Guid clientId, DateTime now, CancellationToken ct = default) { return _dbContext.DeviceCommands .Include(command => command.AccessDeviceBinding) .Where(command => command.FKClientId == clientId && command.Status == "InProgress" && command.LeaseExpiresAt <= now && command.AttemptCount >= command.MaxAttempts) .ToListAsync(ct); } public Task> GetLeaseableCommandsAsync( Guid clientId, Guid agentId, DateTime now, int take, CancellationToken ct = default) { return _dbContext.DeviceCommands .Include(command => command.AccessDevice) .Where(command => command.FKClientId == clientId && command.AccessDevice != null && command.AccessDevice.IsActive && command.AccessDevice.FKAgentId == agentId && ((command.Status == "Pending" && (command.NextAttemptAt == null || command.NextAttemptAt <= now)) || (command.Status == "InProgress" && command.LeaseExpiresAt <= now && command.AttemptCount < command.MaxAttempts))) .OrderBy(command => command.CreatedAt) .Take(take) .ToListAsync(ct); } public Task GetForAgentResultAsync( Guid commandId, CancellationToken ct = default) { return _dbContext.DeviceCommands .Include(command => command.AccessDevice) .Include(command => command.AccessDeviceBinding!) .ThenInclude(binding => binding.AccessProfile) .FirstOrDefaultAsync(command => command.Id == commandId, ct); } public Task UpdateStatusAsync(DeviceCommand command, string status, string? resultJson = null, DateTime? processedAt = null) { command.Status = status; command.ResultJson = resultJson; command.ProcessedAt = processedAt; _dbContext.DeviceCommands.Update(command); return Task.CompletedTask; } } }