using System.Text.Json;
using BigRegister.Api.Data;
using BigRegister.Domain.Applications;
using BigRegister.Domain.Diplomas;
using BigRegister.Domain.Documents;
using BigRegister.Domain.People;
using BigRegister.Domain.Registrations;
namespace BigRegister.Api.Contracts;
/// Domain → wire DTO mapping (the anti-corruption boundary, server side).
public static class Mappers
{
private static string D(DateOnly d) => d.ToString("yyyy-MM-dd");
public static RegistrationStatusDto ToDto(this RegistrationStatus s) => s switch
{
RegistrationStatus.Geregistreerd g => new(s.Tag.ToString(), HerregistratieDatum: D(g.HerregistratieDatum)),
RegistrationStatus.Geschorst g => new(s.Tag.ToString(), GeschorstTot: D(g.GeschorstTot), Reden: g.Reden),
RegistrationStatus.Doorgehaald d => new(s.Tag.ToString(), DoorgehaaldOp: D(d.DoorgehaaldOp), Reden: d.Reden),
_ => throw new ArgumentOutOfRangeException(nameof(s), s, "Unknown RegistrationStatus variant"),
};
public static RegistrationDto ToDto(this Registration r) => new(
r.BigNummer, r.Naam, r.Beroep, D(r.Registratiedatum), D(r.Geboortedatum), r.Status.ToDto());
public static AdresDto ToDto(this Adres a) => new(a.Straat, a.Postcode, a.Woonplaats);
public static PersonDto ToDto(this Person p) => new(p.Naam, D(p.Geboortedatum), p.Adres.ToDto());
public static PolicyQuestionDto ToDto(this PolicyQuestion q) => new(
q.Id, q.Vraag, q.Type == QuestionType.JaNee ? "ja-nee" : "tekst");
public static DuoDiplomaDto ToDto(this Diploma d) => new(
d.Id, d.Naam, d.Instelling, d.Jaar,
DiplomaRules.ProfessionFor(d),
DiplomaRules.QuestionsFor(d).Select(q => q.ToDto()).ToList());
public static DocumentCategoryDto ToDto(this DocumentCategory c) => new(
c.CategoryId, c.Label, c.Description, c.Required, c.AcceptedTypes, c.MaxSizeMb, c.Multiple, c.AllowPostDelivery);
/// Wire projection of an — the null "Concept" case
/// is the one place a status has no , so it becomes the wire
/// convention's magic string here at the boundary rather than living inside the domain type.
/// Shared by and ZgwZaakMapper, so both status producers
/// agree on the projection (WP-68 F3).
public static AanvraagStatusDto ToDto(this AanvraagStatus s) => new(
s.Tag?.ToString() ?? "Concept", s.StepIndex, s.StepCount, s.Referentie, s.Manual, s.Reden);
// Aanvraag status is COMPUTED ON READ (see the StatusAt extension, Data/AanvraagMapper.cs) —
// this is now a one-line projection of that onto the wire DTO (WP-68 F3, WP-73).
public static AanvraagStatusDto ToStatusDto(this Aanvraag a, DateTimeOffset now) => a.StatusAt(now).ToDto();
/// SubmittedAt only exists once Submitted/Decided (WP-73) — null for a Concept,
/// same as the wire DTO's own nullable field.
private static string? SubmittedAtOf(Aanvraag a) => a switch
{
Aanvraag.Concept => null,
Aanvraag.Submitted s => s.SubmittedAt.ToString("o"),
Aanvraag.Decided d => d.SubmittedAt.ToString("o"),
_ => null,
};
/// Draft only exists pre-submission (WP-73) — null once Submitted/Decided (nothing
/// reads it past that point; see AanvraagMapper.ApplyTo's Submitted branch).
private static JsonElement? DraftOf(Aanvraag a) => a is Aanvraag.Concept c ? c.Draft : null;
public static ApplicationSummaryDto ToSummaryDto(this Aanvraag a, DateTimeOffset now) => new(
a.Id, a.Type, a.ToStatusDto(now), a.DocumentIds,
a.CreatedAt.ToString("o"), a.UpdatedAt.ToString("o"), SubmittedAtOf(a));
/// Admin summary — same shape plus the owner (WP-36; the user-facing list leaves Owner null).
public static ApplicationSummaryDto ToAdminSummaryDto(this Aanvraag a, DateTimeOffset now) =>
a.ToSummaryDto(now) with { Owner = a.Owner };
public static ApplicationDetailDto ToDetailDto(this Aanvraag a, DateTimeOffset now) => new(
a.Id, a.Type, a.ToStatusDto(now), DraftOf(a), a.DocumentIds,
a.CreatedAt.ToString("o"), a.UpdatedAt.ToString("o"), SubmittedAtOf(a));
}