using ScadaLink.Commons.Entities.Audit;
using ScadaLink.Commons.Types;
namespace ScadaLink.Communication.Grpc;
///
/// Canonical bridge for Site Call Audit (#22) operational rows between the
/// wire-format exchanged on the
/// CachedCallTelemetry packet and the in-process
/// persistence entity central writes into the SiteCalls table.
///
///
///
/// This mapper lives in ScadaLink.Communication (which owns the generated
/// and references Commons for
/// ) so both SiteStreamGrpcServer and
/// ScadaLink.AuditLog can share one implementation without the
/// project-reference cycle that would result from hosting it in
/// ScadaLink.AuditLog (AuditLog → Communication, never the reverse).
/// Mirrors the sibling .
///
///
/// Only the DTO→entity direction is provided: nothing in the system maps a
/// back onto the wire (sites emit the operational state
/// from SiteCallOperational, never from the central
/// entity), so an entity→DTO method would be dead code.
///
///
/// String nullability convention: proto3 scalar strings cannot be absent, so the
/// optional rehydrates from an empty string back
/// to null. The optional HttpStatus and TerminalAtUtc use proto
/// wrappers so they preserve true null semantics.
///
///
public static class SiteCallDtoMapper
{
///
/// Reconstructs a persistence entity from its
/// wire-format DTO. An empty LastError rehydrates as null; absent
/// HttpStatus/TerminalAtUtc wrappers stay null.
///
///
/// is stamped here as a placeholder
/// (); the central ingest actor overwrites it
/// inside the dual-write transaction so the AuditLog and SiteCalls rows
/// share one instant. The value sent on the wire is informational only.
///
public static SiteCall FromDto(SiteCallOperationalDto dto)
{
ArgumentNullException.ThrowIfNull(dto);
return new SiteCall
{
TrackedOperationId = TrackedOperationId.Parse(dto.TrackedOperationId),
Channel = dto.Channel,
Target = dto.Target,
SourceSite = dto.SourceSite,
SourceNode = string.IsNullOrEmpty(dto.SourceNode) ? null : dto.SourceNode,
Status = dto.Status,
RetryCount = dto.RetryCount,
LastError = string.IsNullOrEmpty(dto.LastError) ? null : dto.LastError,
HttpStatus = dto.HttpStatus,
CreatedAtUtc = DateTime.SpecifyKind(dto.CreatedAtUtc.ToDateTime(), DateTimeKind.Utc),
UpdatedAtUtc = DateTime.SpecifyKind(dto.UpdatedAtUtc.ToDateTime(), DateTimeKind.Utc),
TerminalAtUtc = dto.TerminalAtUtc is null
? null
: DateTime.SpecifyKind(dto.TerminalAtUtc.ToDateTime(), DateTimeKind.Utc),
IngestedAtUtc = DateTime.UtcNow, // overwritten by AuditLogIngestActor
};
}
}