using Zentral.API.Services; using Zentral.Domain.Entities; using Microsoft.AspNetCore.Mvc; namespace Zentral.API.Controllers; /// /// Controller per la gestione dei moduli applicativi e delle subscription /// [ApiController] [Route("api/[controller]")] public class ModulesController : ControllerBase { private readonly ModuleService _moduleService; private readonly ILogger _logger; public ModulesController(ModuleService moduleService, ILogger logger) { _moduleService = moduleService; _logger = logger; } /// /// Ottiene tutti i moduli disponibili con stato subscription /// [HttpGet] public async Task>> GetAllModules() { var modules = await _moduleService.GetAllModulesAsync(); return Ok(modules.Select(MapToDto).ToList()); } /// /// Ottiene solo i moduli attivi (per costruzione menu) /// [HttpGet("active")] public async Task>> GetActiveModules() { var modules = await _moduleService.GetActiveModulesAsync(); return Ok(modules.Select(MapToDto).ToList()); } /// /// Ottiene un modulo specifico per codice /// [HttpGet("{code}")] public async Task> GetModule(string code) { var module = await _moduleService.GetModuleByCodeAsync(code); if (module == null) return NotFound(new { message = $"Modulo '{code}' non trovato" }); return Ok(MapToDto(module)); } /// /// Verifica se un modulo รจ abilitato /// [HttpGet("{code}/enabled")] public async Task> IsModuleEnabled(string code) { var module = await _moduleService.GetModuleByCodeAsync(code); if (module == null) return NotFound(new { message = $"Modulo '{code}' non trovato" }); var isEnabled = await _moduleService.IsModuleEnabledAsync(code); var hasValidSubscription = await _moduleService.HasValidSubscriptionAsync(code); return Ok(new ModuleStatusDto { Code = code, IsEnabled = isEnabled, HasValidSubscription = hasValidSubscription, IsCore = module.IsCore, DaysRemaining = module.Subscription?.GetDaysRemaining(), IsExpiringSoon = module.Subscription?.IsExpiringSoon() ?? false }); } /// /// Attiva un modulo /// [HttpPut("{code}/enable")] public async Task> EnableModule(string code, [FromBody] EnableModuleRequest request) { try { var subscription = await _moduleService.EnableModuleAsync( code, request.SubscriptionType, request.StartDate, request.EndDate, request.AutoRenew, request.PaidPrice, request.Notes); return Ok(MapSubscriptionToDto(subscription)); } catch (ArgumentException ex) { return NotFound(new { message = ex.Message }); } catch (InvalidOperationException ex) { return BadRequest(new { message = ex.Message }); } } /// /// Disattiva un modulo /// [HttpPut("{code}/disable")] public async Task DisableModule(string code) { try { await _moduleService.DisableModuleAsync(code); return Ok(new { message = $"Modulo '{code}' disattivato" }); } catch (ArgumentException ex) { return NotFound(new { message = ex.Message }); } catch (InvalidOperationException ex) { return BadRequest(new { message = ex.Message }); } } /// /// Ottiene tutte le subscription /// [HttpGet("subscriptions")] public async Task>> GetAllSubscriptions() { var subscriptions = await _moduleService.GetAllSubscriptionsAsync(); return Ok(subscriptions.Select(MapSubscriptionToDto).ToList()); } /// /// Aggiorna la subscription di un modulo /// [HttpPut("{code}/subscription")] public async Task> UpdateSubscription(string code, [FromBody] UpdateSubscriptionRequest request) { try { var subscription = await _moduleService.UpdateSubscriptionAsync( code, request.SubscriptionType, request.EndDate, request.AutoRenew, request.Notes); return Ok(MapSubscriptionToDto(subscription)); } catch (ArgumentException ex) { return NotFound(new { message = ex.Message }); } catch (InvalidOperationException ex) { return BadRequest(new { message = ex.Message }); } } /// /// Rinnova la subscription di un modulo /// [HttpPost("{code}/subscription/renew")] public async Task> RenewSubscription(string code, [FromBody] RenewSubscriptionRequest? request = null) { try { var subscription = await _moduleService.RenewSubscriptionAsync(code, request?.PaidPrice); return Ok(MapSubscriptionToDto(subscription)); } catch (ArgumentException ex) { return NotFound(new { message = ex.Message }); } catch (InvalidOperationException ex) { return BadRequest(new { message = ex.Message }); } } /// /// Ottiene i moduli in scadenza /// [HttpGet("expiring")] public async Task>> GetExpiringModules([FromQuery] int daysThreshold = 30) { var modules = await _moduleService.GetExpiringModulesAsync(daysThreshold); return Ok(modules.Select(MapToDto).ToList()); } /// /// Inizializza i moduli di default (per setup iniziale) /// [HttpPost("seed")] public async Task SeedDefaultModules() { await _moduleService.SeedDefaultModulesAsync(); return Ok(new { message = "Moduli di default inizializzati" }); } /// /// Forza il controllo delle subscription scadute /// [HttpPost("check-expired")] public async Task CheckExpiredSubscriptions() { var count = await _moduleService.CheckExpiredSubscriptionsAsync(); return Ok(new { message = $"Controllate le subscription, {count} moduli disattivati per scadenza" }); } /// /// Invalida la cache dei moduli /// [HttpPost("invalidate-cache")] public ActionResult InvalidateCache() { _moduleService.InvalidateCache(); return Ok(new { message = "Cache moduli invalidata" }); } #region Mapping private static ModuleDto MapToDto(AppModule module) { return new ModuleDto { Id = module.Id, Code = module.Code, Name = module.Name, Description = module.Description, Icon = module.Icon, BasePrice = module.BasePrice, MonthlyPrice = module.GetMonthlyPrice(), MonthlyMultiplier = module.MonthlyMultiplier, SortOrder = module.SortOrder, IsCore = module.IsCore, Dependencies = module.GetDependencies().ToList(), RoutePath = module.RoutePath, IsAvailable = module.IsAvailable, IsEnabled = module.IsCore || ((module.Subscription?.IsEnabled ?? false) && (module.Subscription?.IsValid() ?? false)), Subscription = module.Subscription != null ? MapSubscriptionToDto(module.Subscription) : null }; } private static SubscriptionDto MapSubscriptionToDto(ModuleSubscription subscription) { return new SubscriptionDto { Id = subscription.Id, ModuleId = subscription.ModuleId, ModuleCode = subscription.Module?.Code, ModuleName = subscription.Module?.Name, IsEnabled = subscription.IsEnabled, SubscriptionType = subscription.SubscriptionType, SubscriptionTypeName = subscription.SubscriptionType.ToString(), StartDate = subscription.StartDate, EndDate = subscription.EndDate, AutoRenew = subscription.AutoRenew, Notes = subscription.Notes, LastRenewalDate = subscription.LastRenewalDate, PaidPrice = subscription.PaidPrice, IsValid = subscription.IsValid(), DaysRemaining = subscription.GetDaysRemaining(), IsExpiringSoon = subscription.IsExpiringSoon() }; } #endregion } #region DTOs public class ModuleDto { public int Id { get; set; } public string Code { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public string? Description { get; set; } public string? Icon { get; set; } public decimal BasePrice { get; set; } public decimal MonthlyPrice { get; set; } public decimal MonthlyMultiplier { get; set; } public int SortOrder { get; set; } public bool IsCore { get; set; } public List Dependencies { get; set; } = new(); public string? RoutePath { get; set; } public bool IsAvailable { get; set; } public bool IsEnabled { get; set; } public SubscriptionDto? Subscription { get; set; } } public class SubscriptionDto { public int Id { get; set; } public int ModuleId { get; set; } public string? ModuleCode { get; set; } public string? ModuleName { get; set; } public bool IsEnabled { get; set; } public SubscriptionType SubscriptionType { get; set; } public string SubscriptionTypeName { get; set; } = string.Empty; public DateTime? StartDate { get; set; } public DateTime? EndDate { get; set; } public bool AutoRenew { get; set; } public string? Notes { get; set; } public DateTime? LastRenewalDate { get; set; } public decimal? PaidPrice { get; set; } public bool IsValid { get; set; } public int? DaysRemaining { get; set; } public bool IsExpiringSoon { get; set; } } public class ModuleStatusDto { public string Code { get; set; } = string.Empty; public bool IsEnabled { get; set; } public bool HasValidSubscription { get; set; } public bool IsCore { get; set; } public int? DaysRemaining { get; set; } public bool IsExpiringSoon { get; set; } } public class EnableModuleRequest { public SubscriptionType SubscriptionType { get; set; } = SubscriptionType.Annual; public DateTime? StartDate { get; set; } public DateTime? EndDate { get; set; } public bool AutoRenew { get; set; } public decimal? PaidPrice { get; set; } public string? Notes { get; set; } } public class UpdateSubscriptionRequest { public SubscriptionType? SubscriptionType { get; set; } public DateTime? EndDate { get; set; } public bool? AutoRenew { get; set; } public string? Notes { get; set; } } public class RenewSubscriptionRequest { public decimal? PaidPrice { get; set; } } #endregion