using CarneiroTech.Models; using Microsoft.Extensions.Caching.Memory; using System.Globalization; namespace CarneiroTech.Services; public class CaseService : ICaseService { private readonly IMarkdownService _markdownService; private readonly IMemoryCache _cache; private readonly IWebHostEnvironment _environment; private readonly string _casesPath; private const string CACHE_KEY = "cases_retail"; private const int CACHE_MINUTES = 60; public CaseService(IMarkdownService markdownService, IMemoryCache cache, IWebHostEnvironment environment) { _markdownService = markdownService; _cache = cache; _environment = environment; _casesPath = Path.Combine(_environment.ContentRootPath, "Content", "Cases", "Retail"); } public async Task> GetAllCasesAsync() { if (_cache.TryGetValue(CACHE_KEY, out List? cachedCases) && cachedCases != null) { return cachedCases; } var cases = new List(); if (!Directory.Exists(_casesPath)) { return cases; } var markdownFiles = Directory.GetFiles(_casesPath, "*.md"); foreach (var file in markdownFiles) { var caseModel = await ParseCaseFileAsync(file); if (caseModel != null) { cases.Add(caseModel); } } cases = cases.OrderBy(c => c.Metadata.Order) .ThenByDescending(c => c.Metadata.Date) .ToList(); _cache.Set(CACHE_KEY, cases, TimeSpan.FromMinutes(CACHE_MINUTES)); return cases; } public async Task> GetFeaturedCasesAsync() { var allCases = await GetAllCasesAsync(); return allCases.Where(c => c.Metadata.Featured).ToList(); } public async Task GetCaseBySlugAsync(string slug) { var allCases = await GetAllCasesAsync(); return allCases.FirstOrDefault(c => c.Metadata.Slug.Equals(slug, StringComparison.OrdinalIgnoreCase)); } public async Task> GetAllTagsAsync() { var allCases = await GetAllCasesAsync(); return allCases.SelectMany(c => c.Metadata.Tags).Distinct().OrderBy(t => t).ToList(); } public async Task> GetCasesByTagAsync(string tag) { var allCases = await GetAllCasesAsync(); return allCases.Where(c => c.Metadata.Tags.Contains(tag, StringComparer.OrdinalIgnoreCase)).ToList(); } private async Task ParseCaseFileAsync(string filePath) { try { var content = await File.ReadAllTextAsync(filePath); var frontMatter = _markdownService.ParseFrontMatter(content, out string bodyContent); var metadata = new CaseMetadata { Title = GetStringValue(frontMatter, "title"), Slug = GetStringValue(frontMatter, "slug"), Summary = GetStringValue(frontMatter, "summary"), Client = GetStringValue(frontMatter, "client"), DeviceModel = GetStringValue(frontMatter, "device_model"), EstimatedSavings = GetDecimalValue(frontMatter, "estimated_savings"), Category = GetStringValue(frontMatter, "category"), Thumbnail = GetStringValue(frontMatter, "thumbnail"), Image = GetStringValue(frontMatter, "image"), Tags = GetListValue(frontMatter, "tags"), Featured = GetBoolValue(frontMatter, "featured"), Order = GetIntValue(frontMatter, "order"), Date = GetDateValue(frontMatter, "date"), SeoTitle = GetStringValue(frontMatter, "seo_title"), SeoDescription = GetStringValue(frontMatter, "seo_description"), SeoKeywords = GetStringValue(frontMatter, "seo_keywords") }; return new CaseModel { Metadata = metadata, ContentHtml = _markdownService.ConvertToHtml(bodyContent), ContentMarkdown = bodyContent }; } catch { return null; } } private string GetStringValue(Dictionary dict, string key) => dict.ContainsKey(key) ? dict[key]?.ToString() ?? string.Empty : string.Empty; private decimal GetDecimalValue(Dictionary dict, string key) => dict.ContainsKey(key) && decimal.TryParse(dict[key]?.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out decimal res) ? res : 0; private List GetListValue(Dictionary dict, string key) => dict.ContainsKey(key) && dict[key] is List list ? list.Select(i => i?.ToString() ?? "").ToList() : new(); private bool GetBoolValue(Dictionary dict, string key) => dict.ContainsKey(key) && (dict[key]?.ToString()?.ToLower() == "true" || dict[key]?.ToString() == "1"); private int GetIntValue(Dictionary dict, string key) => dict.ContainsKey(key) && int.TryParse(dict[key]?.ToString(), out int res) ? res : 0; private DateTime GetDateValue(Dictionary dict, string key) => dict.ContainsKey(key) && DateTime.TryParse(dict[key]?.ToString(), CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime res) ? res : DateTime.MinValue; }