using System.Text.Json;using Dapper;using FastEndpoints;using Npgsql;
namespace Modules.OMS.Orders.Audit;
public sealed record AuditActor(string Type,string DisplayName);public sealed record AuditChange(string Field,string Label,object? Before,object? After);public sealed record AuditRow(Guid Id,DateTimeOffset OccurredAt,string Actor,string Action,string Data);public sealed record AuditEntry(Guid Id,DateTimeOffset OccurredAt,AuditActor Actor,string Action,IReadOnlyList<AuditChange>? Changes,string? Reason);
public sealed class Endpoint(NpgsqlDataSource dataSource):EndpointWithoutRequest<IReadOnlyList<AuditEntry>>{public override void Configure(){Get("/api/oms/orders/{id}/audit");Permissions("oms.order.read");}public override async Task HandleAsync(CancellationToken ct){var id=Route<Guid>("id");await using var c=await dataSource.OpenConnectionAsync(ct);var rows=await c.QueryAsync<AuditRow>(new CommandDefinition("select id,occurred_at as OccurredAt,actor,action,data::text as Data from audit.entries where aggregate_type='Order' and aggregate_id=@Id order by occurred_at desc limit 100",new{Id=id},cancellationToken:ct));var result=rows.Select(r=>{using var d=JsonDocument.Parse(r.Data);List<AuditChange>? changes=null;if(d.RootElement.TryGetProperty("changes",out var arr)){changes=new();foreach(var x in arr.EnumerateArray())changes.Add(new(x.GetProperty("field").GetString()??"",x.GetProperty("label").GetString()??"",x.TryGetProperty("before",out var b)?b.ToString():null,x.TryGetProperty("after",out var a)?a.ToString():null));}return new AuditEntry(r.Id,r.OccurredAt,new("user",r.Actor),r.Action,changes,null);}).ToList();await Send.OkAsync(result,ct);}}
