using AVSCartonShipmentVerifier.DTOs; using AVSCartonShipmentVerifier.Repositories; namespace AVSCartonShipmentVerifier.Services; public sealed class ShipmentVerificationService( ICartonVerificationRepository repository, IScanHistoryStore historyStore, ILogger logger) : IShipmentVerificationService { private readonly ICartonVerificationRepository _repository = repository; private readonly IScanHistoryStore _historyStore = historyStore; private readonly ILogger _logger = logger; public async Task VerifyQrAsync(string rawQrValue, CancellationToken cancellationToken = default) { var parseResult = TryParseQr(rawQrValue); if (!parseResult.IsValid) { return BuildFailure(parseResult.ErrorMessage); } var nowUtc = DateTime.UtcNow; bool exists; try { exists = await _repository.UniqueNumberExistsAsync(parseResult.UniqueNumber, cancellationToken); } catch (Exception exception) { _logger.LogError(exception, "Verification lookup failed for unique number {UniqueNumber}.", parseResult.UniqueNumber); return BuildFailure("Unable to verify QR at the moment. Please try again."); } if (!exists) { var missingResult = new VerificationResultDto { ModelNumber = parseResult.ModelNumber, UniqueNumber = parseResult.UniqueNumber, RawQrValue = rawQrValue, ExistsInSystem = false, ShipmentMarked = false, Message = "Shipment not completed. Unique number was not found.", ProcessedAtUtc = nowUtc }; _historyStore.Add(ToScannedRecord(missingResult)); return missingResult; } var result = new VerificationResultDto { ModelNumber = parseResult.ModelNumber, UniqueNumber = parseResult.UniqueNumber, RawQrValue = rawQrValue, ExistsInSystem = true, ShipmentMarked = true, Message = "Record found in carton verification log.", ProcessedAtUtc = nowUtc }; _historyStore.Add(ToScannedRecord(result)); return result; } private static (bool IsValid, string ModelNumber, string UniqueNumber, string ErrorMessage) TryParseQr(string rawQrValue) { if (string.IsNullOrWhiteSpace(rawQrValue)) { return (false, string.Empty, string.Empty, "QR value is required."); } if (!rawQrValue.Contains(';')) { return (false, string.Empty, string.Empty, "Invalid QR format. Missing ';' separator. Use modelnumber;uniquenumber."); } var parts = rawQrValue.Split(';', StringSplitOptions.TrimEntries); if (parts.Length != 2) { return (false, string.Empty, string.Empty, "Invalid QR format. Use modelnumber;uniquenumber."); } var modelNumber = parts[0]; var uniqueNumber = parts[1]; if (string.IsNullOrWhiteSpace(uniqueNumber)) { return (false, modelNumber, string.Empty, "Invalid QR format. Unique number is missing after ';'."); } return (true, modelNumber, uniqueNumber, string.Empty); } private static VerificationResultDto BuildFailure(string message) => new() { Message = message, ExistsInSystem = false, ShipmentMarked = false, ProcessedAtUtc = DateTime.UtcNow }; private static ScannedRecordDto ToScannedRecord(VerificationResultDto result) => new() { ModelNumber = result.ModelNumber, UniqueNumber = result.UniqueNumber, ExistsInSystem = result.ExistsInSystem, ShipmentMarked = result.ShipmentMarked, ProcessedAtUtc = result.ProcessedAtUtc }; }