using AiAgent.Core.Helpers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Encodings.Web;
using System.Text.Json;
///
/// A utility class to parse structured article text in JSON format.
///
public static class JsonHelpers
{
///
/// Parses a JSON string representing an article into a dictionary.
/// The dictionary keys are the section titles (e.g., "Title", "Summary", section headings),
/// and the values are the content of those sections.
///
/// The string content of the JSON file.
/// A dictionary mapping section titles to their content.
public static Dictionary SectionParser(string jsonContent)
{
var articleData = new Dictionary();
if (string.IsNullOrWhiteSpace(jsonContent))
{
Console.WriteLine("Warning: Input JSON content is empty or null.");
return articleData;
}
// 2. The Solution: Configure the options
var options = new JsonDocumentOptions // <-- Changed type
{
// This property directly solves your problem
AllowTrailingCommas = true,
// It's also good practice to skip comments, just in case
CommentHandling = JsonCommentHandling.Skip // <-- Changed property name
};
try
{
// Use JsonDocument for efficient, read-only parsing without needing to define a full class structure.
using (JsonDocument doc = JsonDocument.Parse(jsonContent, options))
{
JsonElement root = doc.RootElement;
// Iterate over all top-level properties in the JSON object.
foreach (JsonProperty property in root.EnumerateObject())
{
switch (property.Name)
{
// Handle the "Section" array, which contains multiple headed sections.
case "Section":
if (property.Value.ValueKind == JsonValueKind.Array)
{
foreach (JsonElement sectionElement in property.Value.EnumerateArray())
{
if (sectionElement.TryGetProperty("Heading", out JsonElement heading) &&
sectionElement.TryGetProperty("Content", out JsonElement content))
{
articleData[heading.GetString() ?? ""] = content.GetString() ?? "";
}
}
}
break;
// Handle the "References" array by serializing it back to a string.
case "References":
if (property.Value.ValueKind == JsonValueKind.Array)
{
// Get the raw JSON text of the entire "References" array.
articleData[property.Name] = property.Value.GetRawText();
}
break;
// Handle all other properties that have simple string values.
default:
if (property.Value.ValueKind == JsonValueKind.String)
{
articleData[property.Name] = property.Value.GetString() ?? "";
}
break;
}
}
}
}
catch (JsonException ex)
{
// Handle cases where the input string is not valid JSON.
Console.WriteLine($"Error parsing JSON: {ex.Message}");
// Optionally, rethrow or handle the error as appropriate for your application.
// throw;
}
return articleData;
}
///
/// Inserts a new section into an article's JSON structure after a specified existing section.
///
/// The original JSON string of the article.
/// The heading for the new section to be added.
/// The content for the new section.
/// The heading of the section after which the new section should be inserted.
/// A new, pretty-printed JSON string with the section added, or the original JSON string if the target section isn't found.
public static string InsertSectionAfter(string articleJson, string newSectionHeading, string newSectionContent, string insertAfterHeading)
{
var deserializeOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
try
{
Article? article = JsonSerializer.Deserialize(articleJson, deserializeOptions);
if (article?.Sections == null)
{
Console.WriteLine("Warning: Could not insert section because the article JSON is malformed or contains no sections.");
return articleJson;
}
// Find the index of the section we want to insert after (case-insensitive search)
int targetIndex = article.Sections.FindIndex(s =>
s.Heading?.Equals(insertAfterHeading, StringComparison.OrdinalIgnoreCase) ?? false);
if (targetIndex == -1)
{
Console.WriteLine($"Warning: Section with heading '{insertAfterHeading}' not found. No changes made.");
return articleJson; // Return the original if the target section doesn't exist
}
// Create the new section object
var newSection = new Section
{
Heading = newSectionHeading,
Content = newSectionContent
};
// Insert the new section at the position immediately after the target
article.Sections.Insert(targetIndex + 1, newSection);
// Serialize the modified object back to a pretty-printed JSON string
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
// Use an encoder that doesn't escape characters like apostrophes for better readability
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
return JsonSerializer.Serialize(article, serializeOptions);
}
catch (JsonException ex)
{
Console.WriteLine($"Error: Invalid JSON provided. Details: {ex.Message}");
return articleJson; // Return original JSON on error
}
}
///
/// Checks if a JsonElement (e.g., the root) contains all specified mandatory fields.
///
/// The JsonElement to check.
/// An enumerable of field names that must exist.
/// A list of missing field names. The list is empty if validation succeeds.
public static List CheckMandatoryFields(JsonElement root, IEnumerable mandatoryFields)
{
if (root.ValueKind != JsonValueKind.Object)
{
return mandatoryFields.ToList(); // Or throw an exception, as the root isn't an object
}
var missingFields = new List();
foreach (string field in mandatoryFields)
{
if (!root.TryGetProperty(field, out _))
{
missingFields.Add(field);
}
}
return missingFields;
}
///
/// Checks if all specified fields in a JsonElement have a value kind of 'String'.
/// Assumes fields have already been checked for existence.
///
/// The JsonElement to check.
/// An enumerable of field names to type-check.
/// A list of fields that do not have a String value. Empty if validation succeeds.
public static List CheckFieldsAreString(JsonElement root, IEnumerable fieldsToCheck)
{
if (root.ValueKind != JsonValueKind.Object)
{
return fieldsToCheck.ToList();
}
var nonStringFields = new List();
foreach (string field in fieldsToCheck)
{
// This check is safer, in case the field exists but is null
if (root.TryGetProperty(field, out JsonElement property) && property.ValueKind != JsonValueKind.String)
{
nonStringFields.Add(field);
}
}
return nonStringFields;
}
}