using System.Text.Json; namespace Meezi.Infrastructure.Data; public static class MenuImageManifest { private static IReadOnlyDictionary? _urls; private static string? _defaultDrinkUrl; private static string? _defaultFoodUrl; private const string FallbackDrinkUrl = "https://images.unsplash.com/photo-1509042239860-f550ce710b93?w=600&auto=format&fit=crop"; private const string FallbackFoodUrl = "https://images.unsplash.com/photo-1546793665-c74683f339c1?w=600"; public static string? GetImageUrl(string itemId) { EnsureLoaded(); return _urls!.TryGetValue(itemId, out var url) ? url : null; } public static string GetDefaultDrinkImageUrl() { EnsureLoaded(); return _defaultDrinkUrl ?? FallbackDrinkUrl; } public static string GetDefaultFoodImageUrl() { EnsureLoaded(); return _defaultFoodUrl ?? FallbackFoodUrl; } public static string ResolveImageUrl(string itemId, string fallback) => GetLocalImageOverride(itemId) ?? fallback; /// Only imported Kaggle/upload paths override Food-101 fallbacks (not stale CDN URLs in manifest). public static string? GetLocalImageOverride(string itemId) { var url = GetImageUrl(itemId); if (string.IsNullOrWhiteSpace(url)) return null; if (url.StartsWith("/uploads/", StringComparison.OrdinalIgnoreCase) || url.StartsWith("uploads/", StringComparison.OrdinalIgnoreCase)) return url.StartsWith('/') ? url : $"/{url}"; return null; } private static void EnsureLoaded() { if (_urls is not null) return; LoadFromDisk(); } private static void LoadFromDisk() { var paths = new[] { Path.Combine(AppContext.BaseDirectory, "data", "menu-image-manifest.json"), Path.Combine(Directory.GetCurrentDirectory(), "data", "menu-image-manifest.json"), Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "data", "menu-image-manifest.json")), Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "data", "menu-image-manifest.json")), }; foreach (var path in paths) { if (!File.Exists(path)) continue; try { var json = File.ReadAllText(path); var doc = JsonDocument.Parse(json); if (doc.RootElement.TryGetProperty("defaults", out var defaults)) { if (defaults.TryGetProperty("drink", out var drink)) _defaultDrinkUrl = drink.GetString(); if (defaults.TryGetProperty("food", out var food)) _defaultFoodUrl = food.GetString(); } var map = new Dictionary(StringComparer.Ordinal); if (doc.RootElement.TryGetProperty("items", out var items)) { foreach (var prop in items.EnumerateObject()) { if (prop.Value.TryGetProperty("imageUrl", out var url)) map[prop.Name] = url.GetString() ?? ""; } } _urls = map; return; } catch { // try next path } } _urls = new Dictionary(StringComparer.Ordinal); } }