using Microsoft.AspNetCore.Mvc; using OnlyOneAccessTemplate.Services; using OnlyOneAccessTemplate.Models; using System.Security.Cryptography; using System.Text; using Microsoft.AspNetCore.Http.Extensions; namespace OnlyOneAccessTemplate.Controllers { [Route("api/module-management")] [ApiController] public class ModuleManagementController : ControllerBase { private readonly IModuleService _moduleService; private readonly ILogger _logger; private readonly IConfiguration _configuration; public ModuleManagementController( IModuleService moduleService, ILogger logger, IConfiguration configuration) { _moduleService = moduleService; _logger = logger; _configuration = configuration; } [HttpPost("register")] public async Task RegisterModule([FromBody] ModuleRegistrationRequest request) { try { _logger.LogInformation("Registrando novo módulo: {ModuleId}", request.ModuleId); // Verificar se módulo já existe var existing = await _moduleService.GetModuleConfigAsync(request.ModuleId); if (existing != null) { return BadRequest(new { success = false, message = "Módulo já existe" }); } // Testar conectividade com o módulo var healthUrl = $"{request.BaseUrl.TrimEnd('/')}/{request.HealthEndpoint?.TrimStart('/') ?? "api/converter/health"}"; var isHealthy = await TestModuleHealth(healthUrl); // Gerar API Key var apiKey = GenerateApiKey(); // Criar configuração var moduleConfig = new ModuleConfig { ModuleId = request.ModuleId, Name = request.Name, Url = $"{request.BaseUrl.TrimEnd('/')}/modules/{request.ModuleId}", RequestBy = request.ModuleId, IsActive = request.AutoActivate.HasValue && request.AutoActivate.Value && isHealthy, CacheMinutes = request.CacheMinutes ?? 5, // Proxy Configuration UseProxy = true, ProxyEndpoint = $"/api/modules/{request.ModuleId}", ProxyMappings = new Dictionary { ["convert"] = $"{request.BaseUrl}/api/converter/convert", ["config"] = $"{request.BaseUrl}/api/converter/config", ["health"] = $"{request.BaseUrl}/api/converter/health" }, // Security ApiKey = apiKey, AllowedOrigins = request.AllowedOrigins ?? new List { Request.GetDisplayUrl() }, RateLimitPerMinute = request.RateLimitPerMinute ?? 60, // Menu MenuTitle = request.MenuTitle ?? request.Name, MenuDescription = request.MenuDescription, MenuIcon = request.MenuIcon ?? "fas fa-exchange-alt", MenuCategory = request.MenuCategory ?? "Conversores", MenuOrder = request.MenuOrder ?? 0, ShowInMenu = request.ShowInMenu ?? true, // SEO SeoTitles = request.SeoTitles ?? new Dictionary(), SeoDescriptions = request.SeoDescriptions ?? new Dictionary(), SeoKeywords = request.SeoKeywords ?? new Dictionary(), // Technical HealthEndpoint = request.HealthEndpoint ?? "/api/converter/health", HealthCheckIntervalMinutes = request.HealthCheckIntervalMinutes ?? 5, AutoStart = request.AutoActivate ?? true, Version = request.Version ?? "1.0.0", IsHealthy = isHealthy, LastHealthCheck = DateTime.UtcNow, // Developer DeveloperName = request.DeveloperName, DeveloperEmail = request.DeveloperEmail, Repository = request.Repository, Documentation = request.Documentation, // Headers Headers = new Dictionary { ["X-API-Key"] = apiKey, ["User-Agent"] = "ConvertIt-MainApp/1.0" } }; await _moduleService.SaveModuleConfigAsync(moduleConfig); _logger.LogInformation("Módulo {ModuleId} registrado com sucesso", request.ModuleId); return Ok(new { success = true, message = "Módulo registrado com sucesso", moduleId = request.ModuleId, apiKey = apiKey, proxyEndpoint = moduleConfig.ProxyEndpoint, isHealthy = isHealthy, isActive = moduleConfig.IsActive }); } catch (Exception ex) { _logger.LogError(ex, "Erro ao registrar módulo {ModuleId}", request.ModuleId); return StatusCode(500, new { success = false, message = ex.Message }); } } [HttpGet("modules")] public async Task ListModules() { try { var modules = await _moduleService.GetAllActiveModulesAsync(); var result = modules.Select(m => new { moduleId = m.ModuleId, name = m.Name, isActive = m.IsActive, isHealthy = m.IsHealthy, lastHealthCheck = m.LastHealthCheck, version = m.Version, menuTitle = m.MenuTitle, menuCategory = m.MenuCategory, showInMenu = m.ShowInMenu, developerName = m.DeveloperName, proxyEndpoint = m.ProxyEndpoint }); return Ok(new { success = true, modules = result }); } catch (Exception ex) { _logger.LogError(ex, "Erro ao listar módulos"); return StatusCode(500, new { success = false, message = ex.Message }); } } [HttpPost("modules/{moduleId}/toggle")] public async Task ToggleModule(string moduleId) { try { var module = await _moduleService.GetModuleConfigAsync(moduleId); if (module == null) { return NotFound(new { success = false, message = "Módulo não encontrado" }); } module.IsActive = !module.IsActive; module.UpdatedAt = DateTime.UtcNow; await _moduleService.SaveModuleConfigAsync(module); _logger.LogInformation("Módulo {ModuleId} {Status}", moduleId, module.IsActive ? "ativado" : "desativado"); return Ok(new { success = true, moduleId = moduleId, isActive = module.IsActive, message = $"Módulo {(module.IsActive ? "ativado" : "desativado")} com sucesso" }); } catch (Exception ex) { _logger.LogError(ex, "Erro ao alternar módulo {ModuleId}", moduleId); return StatusCode(500, new { success = false, message = ex.Message }); } } [HttpPost("modules/{moduleId}/health-check")] public async Task CheckModuleHealth(string moduleId) { try { var module = await _moduleService.GetModuleConfigAsync(moduleId); if (module == null) { return NotFound(new { success = false, message = "Módulo não encontrado" }); } var healthUrl = $"{GetBaseUrl(module.Url)}{module.HealthEndpoint}"; var isHealthy = await TestModuleHealth(healthUrl); module.IsHealthy = isHealthy; module.LastHealthCheck = DateTime.UtcNow; await _moduleService.SaveModuleConfigAsync(module); return Ok(new { success = true, moduleId = moduleId, isHealthy = isHealthy, lastCheck = module.LastHealthCheck, healthUrl = healthUrl }); } catch (Exception ex) { _logger.LogError(ex, "Erro ao verificar saúde do módulo {ModuleId}", moduleId); return StatusCode(500, new { success = false, message = ex.Message }); } } [HttpDelete("modules/{moduleId}")] public async Task UnregisterModule(string moduleId) { try { var module = await _moduleService.GetModuleConfigAsync(moduleId); if (module == null) { return NotFound(new { success = false, message = "Módulo não encontrado" }); } // Aqui você implementaria a remoção (dependendo de como está armazenado) // Por enquanto, vamos apenas desativar module.IsActive = false; module.UpdatedAt = DateTime.UtcNow; await _moduleService.SaveModuleConfigAsync(module); _logger.LogInformation("Módulo {ModuleId} desregistrado", moduleId); return Ok(new { success = true, message = "Módulo desregistrado com sucesso" }); } catch (Exception ex) { _logger.LogError(ex, "Erro ao desregistrar módulo {ModuleId}", moduleId); return StatusCode(500, new { success = false, message = ex.Message }); } } private async Task TestModuleHealth(string healthUrl) { try { using var client = new HttpClient(); client.Timeout = TimeSpan.FromSeconds(10); var response = await client.GetAsync(healthUrl); return response.IsSuccessStatusCode; } catch { return false; } } private string GenerateApiKey() { using var rng = RandomNumberGenerator.Create(); var bytes = new byte[32]; rng.GetBytes(bytes); return Convert.ToBase64String(bytes); } private string GetBaseUrl(string fullUrl) { var uri = new Uri(fullUrl); return $"{uri.Scheme}://{uri.Host}:{uri.Port}"; } } public class ModuleRegistrationRequest { public string ModuleId { get; set; } = ""; public string Name { get; set; } = ""; public string BaseUrl { get; set; } = ""; public bool? AutoActivate { get; set; } = true; public int? CacheMinutes { get; set; } = 5; public List? AllowedOrigins { get; set; } public int? RateLimitPerMinute { get; set; } = 60; // Menu public string? MenuTitle { get; set; } public string? MenuDescription { get; set; } public string? MenuIcon { get; set; } public string? MenuCategory { get; set; } public int? MenuOrder { get; set; } public bool? ShowInMenu { get; set; } = true; // SEO public Dictionary? SeoTitles { get; set; } public Dictionary? SeoDescriptions { get; set; } public Dictionary? SeoKeywords { get; set; } // Technical public string? HealthEndpoint { get; set; } public int? HealthCheckIntervalMinutes { get; set; } public string? Version { get; set; } // Developer public string? DeveloperName { get; set; } public string? DeveloperEmail { get; set; } public string? Repository { get; set; } public string? Documentation { get; set; } } }