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<ApplicationDbContext> _dbContextFactory;
        private readonly FeatureDetailsHelper _featureDetailsHelper;
        private readonly IServiceScopeFactory _serviceScopeFactory;
        private readonly IEmailSender _emailSender;
        private readonly IConfiguration _configuration;
        public MarketController(IDbContextFactory<ApplicationDbContext> 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<IActionResult> GetIndustries()
        {
            await using var _context = await _dbContextFactory.CreateDbContextAsync();

            var industries = await _context.Industries.ToListAsync();

            return Ok(ApiResponse<object>.SuccessResponse(industries, "Success.", 200));
        }

        [HttpPost("enquire")]
        public async Task<IActionResult> 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<string> result = emails
                    .Split(';', StringSplitOptions.RemoveEmptyEntries)
                    .Select(item => item.Trim())
                    .ToList();
                await _emailSender.SendRequestDemoEmail(result, inquiryEmailObject);
                return Ok(ApiResponse<object>.SuccessResponse(new { }, "Email sent.", 200));
            }
            return NotFound(ApiResponse<object>.ErrorResponse("Industry not found.", "Industry not found.", 404));
        }

        [HttpGet("list/subscription-plan")]
        public async Task<IActionResult> GetSubscriptionPlanList([FromQuery] PLAN_FREQUENCY? frequency)
        {
            using var scope = _serviceScopeFactory.CreateScope();

            var _logger = scope.ServiceProvider.GetRequiredService<ILoggingService>();
            var _mapper = scope.ServiceProvider.GetRequiredService<IMapper>();
            _logger.LogInfo("GetSubscriptionPlanList called with frequency: {Frequency}", frequency ?? PLAN_FREQUENCY.MONTHLY);

            // Initialize the list to store subscription plan view models
            List<SubscriptionPlanVM> detailsVM = new List<SubscriptionPlanVM>();

            try
            {
                // Create DbContext
                await using var _context = await _dbContextFactory.CreateDbContextAsync();

                // Load subscription plans with optional frequency filtering
                IQueryable<SubscriptionPlanDetails> 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<SubscriptionPlanVM>(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<object>.SuccessResponse(detailsVM, "List of plans fetched successfully", 200));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error occurred while fetching subscription plans");
                return StatusCode(500, ApiResponse<object>.ErrorResponse("An error occurred while fetching subscription plans."));
            }
        }

        [HttpGet("get/project/report/{projectId}")]
        public async Task<IActionResult> GetProjectReport(Guid projectId)
        {
            using var scope = _serviceScopeFactory.CreateScope();
            var _reportHelper = scope.ServiceProvider.GetRequiredService<ReportHelper>();
            var _logger = scope.ServiceProvider.GetRequiredService<ILoggingService>();

            var resonse = await _reportHelper.GetDailyProjectReportWithOutTenant(projectId);

            if (resonse == null)
            {
                _logger.LogWarning("Project report not found");
                return NotFound(ApiResponse<object>.ErrorResponse("Project report not found", "Project report not found", 404));
            }
            _logger.LogInfo("Report for the project fetched successfully");
            return Ok(ApiResponse<object>.SuccessResponse(resonse, "Report for the project fetched successfully", 200));
        }

        /// <summary>
        /// Retrieves a daily project report by its unique identifier.
        /// </summary>
        /// <param name="projectId">The GUID of the project for which to generate the report.</param>
        /// <returns>An IActionResult containing the project report or an appropriate error response.</returns>
        [HttpGet("{projectId}/report")]
        public async Task<IActionResult> GetProjectReportAsync(Guid projectId)
        {
            using var scope = _serviceScopeFactory.CreateScope();
            var _reportHelper = scope.ServiceProvider.GetRequiredService<ReportHelper>();
            var _logger = scope.ServiceProvider.GetRequiredService<ILoggingService>();

            // 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<object>.ErrorResponse("Project report not found.", 404));
                }

                // Log success and return the report.
                _logger.LogInfo("Successfully fetched report for ProjectId: {ProjectId}", projectId);
                return Ok(ApiResponse<object>.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<object>.ErrorResponse("An internal server error occurred while processing the report.", 500));
            }
        }

    }
}
