using System; using System.Collections.Generic; using Newtonsoft.Json; namespace ManagerService.DTOs { /// /// Lenient settings for deserializing online agenda JSON from PHP APIs. /// Any field with an unexpected type (e.g. false instead of string/object) is silently set to null. /// public static class RemoteAgendaJsonSettings { public static readonly JsonSerializerSettings Lenient = new JsonSerializerSettings { Error = (_, args) => { args.ErrorContext.Handled = true; } }; } /// /// Converts boolean false (PHP "no value" pattern) or null to null for object-typed fields. /// public class FalseToNullConverter : JsonConverter { public override bool CanConvert(Type objectType) => true; public override bool CanWrite => false; public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Boolean || reader.TokenType == JsonToken.Null) { reader.Skip(); return null; } var jObject = Newtonsoft.Json.Linq.JObject.Load(reader); var target = Activator.CreateInstance(objectType)!; serializer.Populate(jObject.CreateReader(), target); return target; } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) => throw new NotImplementedException(); } /// /// Specialized DTO for parsing the simplified, localized JSON used by online agendas. /// Matches the structure used in the tablet-app (snake_case). /// public class RemoteEventAgendaDTO { public string? name { get; set; } public string? description { get; set; } public string? type { get; set; } public string? date_added { get; set; } public string? date_from { get; set; } public string? date_to { get; set; } public string? date_hour { get; set; } public string? website { get; set; } public string? phone { get; set; } public string? email { get; set; } public string? id_video_youtube { get; set; } public string? image { get; set; } [JsonConverter(typeof(FalseToNullConverter))] public RemoteEventAddressDTO? address { get; set; } public DateTime? GetDateFrom() => ParseDate(date_from); public DateTime? GetDateTo() => ParseDate(date_to); private DateTime? ParseDate(string? dateStr) { if (string.IsNullOrEmpty(dateStr)) return null; // Handle YYYYMMDD format (e.g. "20260327") if (dateStr.Length == 8 && long.TryParse(dateStr, out _)) if (DateTime.TryParseExact(dateStr, "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out var dt8)) return dt8; if (DateTime.TryParse(dateStr, out var dt)) return dt; return null; } } public class RemoteEventAddressDTO { public string? address { get; set; } public object? lat { get; set; } public object? lng { get; set; } public int? zoom { get; set; } public string? place_id { get; set; } public string? name { get; set; } public string? street_number { get; set; } public string? street_name { get; set; } public string? city { get; set; } public string? state { get; set; } public string? post_code { get; set; } public string? country { get; set; } } }