using Microsoft.Extensions.Caching.Memory; using MongoDB.Driver; using OnlyOneAccessTemplate.Models; namespace OnlyOneAccessTemplate.Services { public class ModuleService : IModuleService { private readonly IMongoDatabase _database; private readonly HttpClient _httpClient; private readonly IMemoryCache _cache; private readonly ILogger _logger; private readonly IMongoCollection _moduleCollection; public ModuleService( IMongoDatabase database, HttpClient httpClient, IMemoryCache cache, ILogger logger) { _database = database; _httpClient = httpClient; _cache = cache; _logger = logger; _moduleCollection = _database.GetCollection("modules"); } public async Task GetModuleConfigAsync(string moduleId) { try { var filter = Builders.Filter.And( Builders.Filter.Eq(x => x.ModuleId, moduleId), Builders.Filter.Eq(x => x.IsActive, true) ); return await _moduleCollection.Find(filter).FirstOrDefaultAsync(); } catch (Exception ex) { _logger.LogError(ex, "Erro ao buscar configuração do módulo {ModuleId}", moduleId); return null; } } public async Task GetModuleContentAsync(string moduleId) { var cacheKey = $"module_content_{moduleId}"; if (_cache.TryGetValue(cacheKey, out string? cachedContent) && !string.IsNullOrEmpty(cachedContent)) { return cachedContent; } var config = await GetModuleConfigAsync(moduleId); if (config == null) { return "

Módulo não encontrado.

"; } var content = await FetchContentFromUrlAsync(config.Url, config.Headers); // Cache por X minutos conforme configuração _cache.Set(cacheKey, content, TimeSpan.FromMinutes(config.CacheMinutes)); return content; } public async Task FetchContentFromUrlAsync(string url, Dictionary? headers = null) { try { using var request = new HttpRequestMessage(HttpMethod.Get, url); if (headers != null) { foreach (var header in headers) { request.Headers.TryAddWithoutValidation(header.Key, header.Value); } } using var response = await _httpClient.SendAsync(request); if (response.IsSuccessStatusCode) { return await response.Content.ReadAsStringAsync(); } _logger.LogWarning("Falha ao buscar conteúdo de {Url}. Status: {StatusCode}", url, response.StatusCode); return "

Conteúdo temporariamente indisponível.

"; } catch (Exception ex) { _logger.LogError(ex, "Erro ao buscar conteúdo de {Url}", url); return "

Erro ao carregar conteúdo.

"; } } public async Task> GetAllActiveModulesAsync() { var filter = Builders.Filter.Eq(x => x.IsActive, true); return await _moduleCollection.Find(filter).ToListAsync(); } public async Task SaveModuleConfigAsync(ModuleConfig config) { config.UpdatedAt = DateTime.UtcNow; if (string.IsNullOrEmpty(config.Id)) { config.CreatedAt = DateTime.UtcNow; await _moduleCollection.InsertOneAsync(config); } else { var filter = Builders.Filter.Eq(x => x.Id, config.Id); await _moduleCollection.ReplaceOneAsync(filter, config); } } } }