using Data.SeaHavenIndustries; using Data.SeaHavenIndustries.Enums; using Microsoft.EntityFrameworkCore; using SeaHaven.DataServices.Interfaces; namespace SeaHaven.DataServices.Implementation { public class ServicesRegistryDataService : IServicesRegistryDataService { private readonly ApplicationDbContext _context; public ServicesRegistryDataService(ApplicationDbContext context) { _context = context; } public async Task> GetServiceRowsAsync(bool? isActive, WorkOrderType? workOrderType, CancellationToken cancellationToken) { var query = _context.Services .AsNoTracking() .Where(s => s.IsDeleted != true); if (isActive.HasValue) query = query.Where(s => s.IsActive == isActive.Value); if (workOrderType.HasValue) query = query.Where(s => s.SupportedWorkOrderTypes.Any(t => t.WorkOrderType == workOrderType.Value)); var rows = await query .OrderBy(s => s.Name) .Select(s => new ServiceRegistryRow { Id = s.Id, Name = s.Name, Trade = s.Trade, IconKey = s.IconKey, RequiresCompletionDocument = s.RequiresCompletionDocument, IsActive = s.IsActive, CompletionDocTemplateId = s.CompletionDocTemplateId, CompletionDocTemplateName = s.CompletionDocTemplate != null ? s.CompletionDocTemplate.Name : null, SupportedWorkOrderTypes = s.SupportedWorkOrderTypes.Select(t => t.WorkOrderType).ToList() }) .ToListAsync(cancellationToken); return rows; } public async Task GetServiceRowByIdAsync(int id, CancellationToken cancellationToken) { return await _context.Services.AsNoTracking() .Where(s => s.Id == id && s.IsDeleted != true) .Select(s => new ServiceRegistryRow { Id = s.Id, Name = s.Name, Trade = s.Trade, IconKey = s.IconKey, RequiresCompletionDocument = s.RequiresCompletionDocument, IsActive = s.IsActive, CompletionDocTemplateId = s.CompletionDocTemplateId, CompletionDocTemplateName = s.CompletionDocTemplate != null ? s.CompletionDocTemplate.Name : null, SupportedWorkOrderTypes = s.SupportedWorkOrderTypes.Select(t => t.WorkOrderType).ToList() }) .FirstOrDefaultAsync(cancellationToken); } public async Task GetServiceForUpdateAsync(int id, CancellationToken cancellationToken) { return await _context.Services .Include(s => s.SupportedWorkOrderTypes) .FirstOrDefaultAsync(s => s.Id == id && s.IsDeleted != true, cancellationToken); } public async Task NormalizedNameExistsAsync(string normalizedName, int? excludeServiceId, CancellationToken cancellationToken) { return await _context.Services .AnyAsync(s => s.IsDeleted != true && s.NormalizedName == normalizedName && (excludeServiceId == null || s.Id != excludeServiceId), cancellationToken); } public async Task GetActiveTemplateSummaryAsync(int templateId, CancellationToken cancellationToken) { return await _context.CompletionDocTemplates .Where(t => t.Id == templateId && t.IsActive && t.IsDeleted != true) .Select(t => new LinkedTemplateSummary { Id = t.Id, Name = t.Name }) .FirstOrDefaultAsync(cancellationToken); } public async Task AddServiceAsync(Service service, CancellationToken cancellationToken) { await _context.Services.AddAsync(service, cancellationToken); await _context.SaveChangesAsync(cancellationToken); return service; } public async Task SaveServiceAsync(Service service, IReadOnlyCollection supportedWorkOrderTypes, CancellationToken cancellationToken) { var desired = supportedWorkOrderTypes.Distinct().ToList(); var current = service.SupportedWorkOrderTypes ?? new List(); var stale = current.Where(t => !desired.Contains(t.WorkOrderType)).ToList(); _context.ServiceWorkOrderTypes.RemoveRange(stale); var existingTypes = current.Select(t => t.WorkOrderType).ToHashSet(); foreach (var type in desired.Where(t => !existingTypes.Contains(t))) { _context.ServiceWorkOrderTypes.Add(new ServiceWorkOrderType { ServiceId = service.Id, WorkOrderType = type }); } await _context.SaveChangesAsync(cancellationToken); } public async Task DeactivateServiceAsync(int id, CancellationToken cancellationToken) { var service = await _context.Services .FirstOrDefaultAsync(s => s.Id == id && s.IsDeleted != true, cancellationToken); if (service == null) return false; service.IsActive = false; await _context.SaveChangesAsync(cancellationToken); return true; } } }