using Microsoft.EntityFrameworkCore; using vendorApproverBackend.Data; using vendorApproverBackend.Entities; using vendorApproverBackend.Requests; using vendorApproverBackend.Exceptions; namespace vendorApproverBackend.Services { public class ApplicationCategoryService { private readonly DataContext _context; public ApplicationCategoryService(DataContext context) { _context = context; } public async Task SaveChangesAsync() { await _context.SaveChangesAsync(); } public async Task AddApplicationCategoryAsync(AddApplicationCategoryRequest request) { // Check for existing Name or NameAr bool exists = await _context.ApplicationCategories .AnyAsync(a => a.Name == request.Name || a.NameAr == request.NameAr); if (exists) { throw new BadRequestException("ApplicationCategory with this Name or NameAr already exists."); } var appCategory = new ApplicationCategory { Name = request.Name, NameAr = request.NameAr, Timestamp = DateTime.UtcNow }; if (request.Categories != null) { appCategory.Categories.AddRange(request.Categories.Select(c => new Category { Label = c.Label, LabelAr = c.LabelAr })); } _context.ApplicationCategories.Add(appCategory); await _context.SaveChangesAsync(); return appCategory; } public async Task FindApplicationCategoryByIdAsync(long id) { var appCategory = await _context.ApplicationCategories .Include(a => a.Categories) .FirstOrDefaultAsync(a => a.Id == id); if (appCategory == null) { throw new NotFoundException($"ApplicationCategory with ID {id} not found."); } return appCategory; } public async Task> FetchAllApplicationCategoryAsync() { return await _context.ApplicationCategories .Include(a => a.Categories) .OrderBy(a => a.Name) .ToListAsync(); } public async Task UpdateApplicationCategoryAsync(long id, UpdateApplicationCategoryRequest request) { var appCategory = await FindApplicationCategoryByIdAsync(id); // Conditional updates (check if input attribute is NOT NULL) if (!string.IsNullOrEmpty(request.Name)) { // Optional: Check if the new name is not a duplicate of *another* category bool nameExists = await _context.ApplicationCategories .AnyAsync(a => a.Id != id && a.Name == request.Name); if (nameExists) throw new BadRequestException("Name already exists in another category."); appCategory.Name = request.Name; } if (!string.IsNullOrEmpty(request.NameAr)) { bool nameArExists = await _context.ApplicationCategories .AnyAsync(a => a.Id != id && a.NameAr == request.NameAr); if (nameArExists) throw new BadRequestException("NameAr already exists in another category."); appCategory.NameAr = request.NameAr; } await _context.SaveChangesAsync(); return appCategory; } public async Task DeleteApplicationCategoryAsync(long id) { var appCategory = await FindApplicationCategoryByIdAsync(id); // Throws NotFound if not found _context.ApplicationCategories.Remove(appCategory); // Cascading delete should handle the child Categories due to OnDelete(DeleteBehavior.Cascade) in DbContext await _context.SaveChangesAsync(); } // --- Categories Sub-Feature Operations --- public async Task AddCategoriesToAppCategoryAsync(long appCategoryId, CategoryRequest request) { var appCategory = await FindApplicationCategoryByIdAsync(appCategoryId); // Ensures parent exists var newCategory = new Category { Label = request.Label, LabelAr = request.LabelAr, ApplicationCategoryId = appCategory.Id // Set foreign key }; _context.Categories.Add(newCategory); await _context.SaveChangesAsync(); return newCategory; } public async Task FindCategoryByIdAsync(long categoryId) { var category = await _context.Categories .FirstOrDefaultAsync(c => c.Id == categoryId); if (category == null) { throw new NotFoundException($"Category with ID {categoryId} not found."); } return category; } public async Task UpdateCategoryAsync(long categoryId, UpdateCategoryByIdRequest request) { var category = await FindCategoryByIdAsync(categoryId); if (request.Label != null) { category.Label = request.Label; } if (request.LabelAr != null) { category.LabelAr = request.LabelAr; } await _context.SaveChangesAsync(); return category; } public async Task DeleteCategoryAsync(long categoryId) { var category = await FindCategoryByIdAsync(categoryId); _context.Categories.Remove(category); await _context.SaveChangesAsync(); } public async Task ExistsByNameAsync(string name) { return await _context.ApplicationCategories .Include(a => a.Categories) .FirstOrDefaultAsync(a => a.Name == name); } public bool CategoryExistsByLabel(ApplicationCategory appCategory, string label) { return appCategory.Categories.Any(c => c.Label == label); } public async Task AddApplicationCategoryAsync(AddApplicationCategoryRequest request, bool skipExistenceCheck = false) { if (!skipExistenceCheck) { bool exists = await _context.ApplicationCategories .AnyAsync(a => a.Name == request.Name || a.NameAr == request.NameAr); if (exists) { throw new BadRequestException("ApplicationCategory with this Name or NameAr already exists."); } } var appCategory = new ApplicationCategory { Name = request.Name, NameAr = request.NameAr, Timestamp = DateTime.UtcNow }; if (request.Categories != null) { appCategory.Categories.AddRange(request.Categories.Select(c => new Category { Label = c.Label, LabelAr = c.LabelAr })); } _context.ApplicationCategories.Add(appCategory); await _context.SaveChangesAsync(); return appCategory; } } }