using AutoMapper; using Marco.Pms.DataAccess.Data; using Marco.Pms.Helpers.Utility; using Marco.Pms.Model.Dtos.Util; using Marco.Pms.Model.Mapper; using Marco.Pms.Model.Master; using Marco.Pms.Model.TenantModels; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Tenant; using Marco.Pms.Services.Helpers; using MarcoBMS.Services.Service; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace Marco.Pms.Services.Controllers { [Route("api/[controller]")] [ApiController] public class MarketController : ControllerBase { private readonly IDbContextFactory _dbContextFactory; private readonly FeatureDetailsHelper _featureDetailsHelper; private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IEmailSender _emailSender; private readonly IConfiguration _configuration; public MarketController(IDbContextFactory dbContextFactory, IServiceScopeFactory serviceScopeFactory, IEmailSender emailSender, IConfiguration configuration, FeatureDetailsHelper featureDetailsHelper) { _dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory)); _serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory)); _emailSender = emailSender ?? throw new ArgumentNullException(nameof(emailSender)); _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); _featureDetailsHelper = featureDetailsHelper ?? throw new ArgumentNullException(nameof(featureDetailsHelper)); } [HttpGet] [Route("industries")] public async Task GetIndustries() { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var industries = await _context.Industries.ToListAsync(); return Ok(ApiResponse.SuccessResponse(industries, "Success.", 200)); } [HttpPost("enquire")] public async Task RequestDemo([FromBody] InquiryDto inquiryDto) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); Inquiries inquiry = inquiryDto.ToInquiriesFromInquiriesDto(); _context.Inquiries.Add(inquiry); await _context.SaveChangesAsync(); Industry industry = await _context.Industries.FirstOrDefaultAsync(i => i.Id == inquiryDto.IndustryId) ?? new Industry(); if (industry != null && industry.Name != null) { InquiryEmailObject inquiryEmailObject = inquiryDto.ToInquiryEmailObjectFromInquiriesDto(industry.Name); string emails = _configuration["MailingList:RequestDemoReceivers"] ?? ""; List result = emails .Split(';', StringSplitOptions.RemoveEmptyEntries) .Select(item => item.Trim()) .ToList(); await _emailSender.SendRequestDemoEmail(result, inquiryEmailObject); return Ok(ApiResponse.SuccessResponse(new { }, "Email sent.", 200)); } return NotFound(ApiResponse.ErrorResponse("Industry not found.", "Industry not found.", 404)); } [HttpGet("list/subscription-plan")] public async Task GetSubscriptionPlanList([FromQuery] PLAN_FREQUENCY? frequency) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); var _mapper = scope.ServiceProvider.GetRequiredService(); _logger.LogInfo("GetSubscriptionPlanList called with frequency: {Frequency}", frequency ?? PLAN_FREQUENCY.MONTHLY); // Initialize the list to store subscription plan view models List detailsVM = new List(); try { // Create DbContext await using var _context = await _dbContextFactory.CreateDbContextAsync(); // Load subscription plans with optional frequency filtering IQueryable query = _context.SubscriptionPlanDetails.Include(sp => sp.Plan).Include(sp => sp.Currency); if (frequency.HasValue) { query = query.Where(sp => sp.Frequency == frequency.Value); _logger.LogInfo("Filtering subscription plans by frequency: {Frequency}", frequency); } else { _logger.LogInfo("Fetching all subscription plans without frequency filter"); } var subscriptionPlans = await query.ToListAsync(); // Map and fetch feature details for each subscription plan foreach (var subscriptionPlan in subscriptionPlans) { var response = _mapper.Map(subscriptionPlan); try { response.Features = await _featureDetailsHelper.GetFeatureDetails(subscriptionPlan.FeaturesId); } catch (Exception exFeature) { _logger.LogError(exFeature, "Failed to fetch features for FeaturesId: {FeaturesId}", subscriptionPlan.FeaturesId); response.Features = null; // or set to a default/fallback value } detailsVM.Add(response); } _logger.LogInfo("Successfully fetched {Count} subscription plans", detailsVM.Count); return Ok(ApiResponse.SuccessResponse(detailsVM, "List of plans fetched successfully", 200)); } catch (Exception ex) { _logger.LogError(ex, "Error occurred while fetching subscription plans"); return StatusCode(500, ApiResponse.ErrorResponse("An error occurred while fetching subscription plans.")); } } [HttpGet("get/project/report/{projectId}")] public async Task GetProjectReport(Guid projectId) { using var scope = _serviceScopeFactory.CreateScope(); var _reportHelper = scope.ServiceProvider.GetRequiredService(); var _logger = scope.ServiceProvider.GetRequiredService(); var resonse = await _reportHelper.GetDailyProjectReportWithOutTenant(projectId); if (resonse == null) { _logger.LogWarning("Project report not found"); return NotFound(ApiResponse.ErrorResponse("Project report not found", "Project report not found", 404)); } _logger.LogInfo("Report for the project fetched successfully"); return Ok(ApiResponse.SuccessResponse(resonse, "Report for the project fetched successfully", 200)); } /// /// Retrieves a daily project report by its unique identifier. /// /// The GUID of the project for which to generate the report. /// An IActionResult containing the project report or an appropriate error response. [HttpGet("{projectId}/report")] public async Task GetProjectReportAsync(Guid projectId) { using var scope = _serviceScopeFactory.CreateScope(); var _reportHelper = scope.ServiceProvider.GetRequiredService(); var _logger = scope.ServiceProvider.GetRequiredService(); // Use structured logging to include the projectId for better traceability. _logger.LogInfo("Attempting to fetch report for ProjectId: {ProjectId}", projectId); try { // Call the helper service, which is now available as a class member. var response = await _reportHelper.GetDailyProjectReportWithOutTenant(projectId); // Check if the report data was found. if (response == null) { _logger.LogWarning("Project report not found for ProjectId: {ProjectId}", projectId); return NotFound(ApiResponse.ErrorResponse("Project report not found.", 404)); } // Log success and return the report. _logger.LogInfo("Successfully fetched report for ProjectId: {ProjectId}", projectId); return Ok(ApiResponse.SuccessResponse(response, "Report for the project fetched successfully.", 200)); } catch (Exception ex) { // Log the full exception if anything goes wrong during the process. _logger.LogError(ex, "An error occurred while generating the report for ProjectId: {ProjectId}", projectId); // Return a standardized 500 Internal Server Error response to the client. return StatusCode(500, ApiResponse.ErrorResponse("An internal server error occurred while processing the report.", 500)); } } } }