using AutoMapper; using GreenHome.Application; using Microsoft.EntityFrameworkCore; namespace GreenHome.Infrastructure; public sealed class ChecklistService : IChecklistService { private readonly GreenHomeDbContext _context; private readonly IMapper _mapper; public ChecklistService(GreenHomeDbContext context, IMapper mapper) { _context = context; _mapper = mapper; } public async Task GetActiveChecklistByDeviceIdAsync(int deviceId, CancellationToken cancellationToken) { var checklist = await _context.Checklists .Include(c => c.Device) .Include(c => c.CreatedByUser) .Include(c => c.Items.OrderBy(i => i.Order)) .AsNoTracking() .FirstOrDefaultAsync(c => c.DeviceId == deviceId && c.IsActive, cancellationToken); return checklist != null ? _mapper.Map(checklist) : null; } public async Task> GetChecklistsByDeviceIdAsync(int deviceId, CancellationToken cancellationToken) { var checklists = await _context.Checklists .Include(c => c.Device) .Include(c => c.CreatedByUser) .Include(c => c.Items.OrderBy(i => i.Order)) .AsNoTracking() .Where(c => c.DeviceId == deviceId) .OrderByDescending(c => c.IsActive) .ThenByDescending(c => c.CreatedAt) .ToListAsync(cancellationToken); return _mapper.Map>(checklists); } public async Task GetChecklistByIdAsync(int id, CancellationToken cancellationToken) { var checklist = await _context.Checklists .Include(c => c.Device) .Include(c => c.CreatedByUser) .Include(c => c.Items.OrderBy(i => i.Order)) .AsNoTracking() .FirstOrDefaultAsync(c => c.Id == id, cancellationToken); return checklist != null ? _mapper.Map(checklist) : null; } public async Task CreateChecklistAsync(CreateChecklistRequest request, CancellationToken cancellationToken) { // Deactivate existing active checklist for this device var existingActiveChecklist = await _context.Checklists .FirstOrDefaultAsync(c => c.DeviceId == request.DeviceId && c.IsActive, cancellationToken); if (existingActiveChecklist != null) { existingActiveChecklist.IsActive = false; } // Create new checklist var checklist = new Domain.Checklist { DeviceId = request.DeviceId, CreatedByUserId = request.CreatedByUserId, Title = request.Title, Description = request.Description, IsActive = true, CreatedAt = DateTime.UtcNow }; // Add items foreach (var itemRequest in request.Items) { var item = new Domain.ChecklistItem { Title = itemRequest.Title, Description = itemRequest.Description, Order = itemRequest.Order, IsRequired = itemRequest.IsRequired }; checklist.Items.Add(item); } _context.Checklists.Add(checklist); await _context.SaveChangesAsync(cancellationToken); return checklist.Id; } public async Task> GetCompletionsByChecklistIdAsync( int checklistId, CancellationToken cancellationToken) { var completions = await _context.ChecklistCompletions .Include(cc => cc.Checklist) .Include(cc => cc.CompletedByUser) .Include(cc => cc.ItemCompletions) .ThenInclude(ic => ic.ChecklistItem) .AsNoTracking() .Where(cc => cc.ChecklistId == checklistId) .OrderByDescending(cc => cc.CompletedAt) .ToListAsync(cancellationToken); return _mapper.Map>(completions); } public async Task CompleteChecklistAsync(CompleteChecklistRequest request, CancellationToken cancellationToken) { var checklist = await _context.Checklists .Include(c => c.Items) .FirstOrDefaultAsync(c => c.Id == request.ChecklistId, cancellationToken); if (checklist == null) { throw new InvalidOperationException($"چک‌لیست با شناسه {request.ChecklistId} یافت نشد"); } var completion = new Domain.ChecklistCompletion { ChecklistId = request.ChecklistId, CompletedByUserId = request.CompletedByUserId, PersianDate = request.PersianDate, Notes = request.Notes, CompletedAt = DateTime.UtcNow }; foreach (var itemCompletion in request.ItemCompletions) { var item = new Domain.ChecklistItemCompletion { ChecklistItemId = itemCompletion.ChecklistItemId, IsChecked = itemCompletion.IsChecked, Note = itemCompletion.Note }; completion.ItemCompletions.Add(item); } _context.ChecklistCompletions.Add(completion); await _context.SaveChangesAsync(cancellationToken); return completion.Id; } }