using System.Text.Json;
using System.Text.Json.Nodes;
using SoroushAsadi.Data;
namespace SoroushAsadi.Services;
///
/// Merges hardcoded default content with admin overrides stored in SQLite.
/// Sections are keyed by name ("hero", "services", etc.).
/// The stored JSON is {"fa": {...}, "en": {...}} for bilingual sections,
/// or a slug-keyed map for "posts".
///
public class ContentService(AppDbContext db)
{
private static readonly JsonSerializerOptions _json =
new() { PropertyNameCaseInsensitive = true };
// ── Public API ────────────────────────────────────────────────────────
/// Returns the merged content for a section as a JsonNode.
/// Callers get the locale-specific sub-object (e.g. node["en"]).
public JsonNode? GetSection(string key)
{
try
{
var row = db.ContentSections.Find(key);
if (row is null) return null;
return JsonNode.Parse(row.DataJson);
}
catch { return null; }
}
/// Returns merged bilingual content for the given section + locale.
public JsonNode? GetSectionLocale(string key, string locale)
{
var node = GetSection(key);
return node?[locale];
}
/// Returns all section rows (for admin listing).
public IReadOnlyList GetSectionKeys() =>
db.ContentSections.Select(s => s.Key).ToList();
/// Upserts a section's JSON data.
public void SaveSection(string key, string json)
{
var row = db.ContentSections.Find(key);
if (row is null)
{
row = new Models.ContentSection { Key = key };
db.ContentSections.Add(row);
}
row.DataJson = json;
row.UpdatedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
db.SaveChanges();
}
/// Deletes a section override (restores built-in default).
public void DeleteSection(string key)
{
var row = db.ContentSections.Find(key);
if (row is not null)
{
db.ContentSections.Remove(row);
db.SaveChanges();
}
}
// ── Posts (stored under key "posts") ─────────────────────────────────
public const string PostsKey = "posts";
/// Returns the slug→PostContent map from DB, or empty.
public Dictionary GetPostOverrides()
{
try
{
var row = db.ContentSections.Find(PostsKey);
if (row is null) return [];
var parsed = JsonNode.Parse(row.DataJson);
if (parsed is not JsonObject obj) return [];
return obj.ToDictionary(kv => kv.Key, kv => kv.Value!);
}
catch { return []; }
}
/// Saves a single post override.
public void SavePost(string slug, JsonNode content)
{
var row = db.ContentSections.Find(PostsKey);
JsonObject obj;
if (row is null)
{
obj = [];
row = new Models.ContentSection { Key = PostsKey };
db.ContentSections.Add(row);
}
else
{
obj = JsonNode.Parse(row.DataJson) as JsonObject ?? [];
}
obj[slug] = content.DeepClone();
row.DataJson = obj.ToJsonString();
row.UpdatedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
db.SaveChanges();
}
}