using Big.Domain;
namespace Big.Application;
/// A behandelaar's beoordeling outcome, in domain language.
public enum BeoordelingsBesluit
{
/// Approve โ enter the registration in the register.
Goedkeuren,
/// Reject โ turn the registration down.
Afwijzen,
}
/// A behandelaar's decision on a registration.
public sealed record BeoordeelRegistratieCommand(RegistrationId RegistrationId, BeoordelingsBesluit Besluit);
///
/// The beoordeling use case (S-12): apply a behandelaar's decision to a registration.
/// sets the zaak's final status via the ACL (ยง8.1) and
/// advances the aggregate to INGESCHREVEN; advances it to
/// AFGEWEZEN in the domain (propagating a rejection to the zaak, so the openbaar projection reflects
/// it, is a later sub-slice of S-12). Both decisions are idempotent โ a repeated or redelivered
/// decision that matches the current terminal state is a no-op, so the ACL is not called twice.
///
public sealed class BeoordeelRegistratie(IRegistrationStore store, IAclClient acl)
{
public async Task HandleAsync(BeoordeelRegistratieCommand command, CancellationToken ct = default)
{
ArgumentNullException.ThrowIfNull(command);
var registration = await store.GetAsync(command.RegistrationId, ct)
?? throw new InvalidOperationException($"No registration {command.RegistrationId} to decide.");
switch (command.Besluit)
{
case BeoordelingsBesluit.Goedkeuren:
// A repeated approval is a no-op: don't set the zaak status a second time.
if (registration.Status == RegistrationStatus.Ingeschreven)
return;
if (registration.ZaakUrl is null)
throw new InvalidOperationException(
$"Registration {command.RegistrationId} has no zaak yet; it cannot be approved.");
await acl.ApproveZaakAsync(registration.ZaakUrl, ct);
registration.Approve();
break;
case BeoordelingsBesluit.Afwijzen:
if (registration.Status == RegistrationStatus.Afgewezen)
return;
registration.Reject();
break;
}
await store.SaveAsync(registration, ct);
}
}