using AutoMapper; using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Master; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Services.Helpers; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace MarcoBMS.Services.Controllers { [Route("api/[controller]")] [ApiController] // [Authorize] public class FeatureController : ControllerBase { private readonly ApplicationDbContext _context; private readonly GeneralHelper _generalHelper; //private readonly UserHelper _userHelper; private readonly IMapper _mapper; private readonly ILoggingService _logger; private readonly Guid tenantId; public FeatureController(ApplicationDbContext context, GeneralHelper generalHelper, UserHelper userHelper, IMapper mapper, ILoggingService logger) { _context = context; _generalHelper = generalHelper; //_userHelper = userHelper; _mapper = mapper; _logger = logger; tenantId = userHelper.GetTenantId(); } private ICollection GetFeaturePermissionVM(Feature model) { if (model.FeaturePermissions == null) { return []; } ICollection features = model.FeaturePermissions.Select(p => _mapper.Map(p)).OrderBy(f => f.Name).ToList(); return features; } [HttpGet("features")] public async Task GetAllFeatures() { List featureIds = await _generalHelper.GetFeatureIdsByTenentId(tenantId); var roles = await _context.Features .Include(f => f.FeaturePermissions) .Include(f => f.Module) .Where(f => featureIds.Contains(f.Id)) .ToListAsync(); var rolesVM = roles.Select(c => new FeatureVM() { Id = c.Id, Name = c.Name, Description = c.Description, FeaturePermissions = GetFeaturePermissionVM(c), ModuleId = c.ModuleId, ModuleName = c.Module != null ? c.Module.Name : string.Empty, IsActive = c.IsActive }).OrderBy(f => f.Name).ToList(); return Ok(ApiResponse.SuccessResponse(rolesVM, "Success.", 200)); } /// /// Converts FeaturePermissions from Feature entity into FeaturePermissionVM collection. /// /// Feature entity from DB /// Collection of FeaturePermissionVM, ordered by Name private ICollection GetFeaturePermissionVMs(Feature model) { if (model.FeaturePermissions == null || !model.FeaturePermissions.Any()) { _logger.LogInfo("No feature permissions found for Feature: {FeatureId}", model.Id); return new List(); } // Project and order feature permissions var features = model.FeaturePermissions .Select(p => _mapper.Map(p)) .OrderBy(f => f.Name) .ToList(); _logger.LogDebug("Mapped {Count} feature permissions for Feature: {FeatureId}", features.Count, model.Id); return features; } /// /// API endpoint to fetch all features and their permissions for the given tenant. /// [HttpGet] public async Task GetAllFeaturesAsync() { try { _logger.LogInfo("Fetching all features for tenant: {TenantId}", tenantId); // Step 1: Get tenant-specific FeatureIds List featureIds = await _generalHelper.GetFeatureIdsByTenentIdAsync(tenantId); if (featureIds == null || !featureIds.Any()) { _logger.LogWarning("No features found for tenant: {TenantId}", tenantId); return Ok(ApiResponse.SuccessResponse(new List(), "No features found.", 200)); } _logger.LogDebug("Retrieved {Count} feature IDs for tenant: {TenantId}", featureIds.Count, tenantId); // Step 2: Query Features with related FeaturePermissions & Module var features = await _context.Features .AsNoTracking() // Optimization: Read-only query .Include(f => f.FeaturePermissions) .Include(f => f.Module) .Where(f => featureIds.Contains(f.Id)) .ToListAsync(); _logger.LogDebug("Fetched {Count} features from DB for tenant: {TenantId}", features.Count, tenantId); // Step 3: Map features to ViewModels var featureVMs = features .Select(c => new FeatureVM { Id = c.Id, Name = c.Name, Description = c.Description, FeaturePermissions = GetFeaturePermissionVMs(c), ModuleId = c.ModuleId, ModuleName = c.Module?.Name ?? string.Empty, IsActive = c.IsActive }) .OrderBy(f => f.Name) .ToList(); _logger.LogInfo("Returning {Count} features for tenant: {TenantId}", featureVMs.Count, tenantId); return Ok(ApiResponse.SuccessResponse(featureVMs, "Success.", 200)); } catch (Exception ex) { _logger.LogError(ex, "Error while fetching features for tenant: {TenantId}", tenantId); return StatusCode(500, ApiResponse.ErrorResponse("An unexpected error occurred.", 500)); } } } }